使用数组的 DocumentDB 查询
DocumentDB queries with arrays
我有包含简单(字符串)数组的文档 属性。
{
"id": "one",
"tags": ["A", "B"]
}
{
"id": "two",
"tags": ["A", "C"]
}
要检查某个值是否是数组的一部分,我可以使用 ARRAY_CONTAINS
SELECT * FROM c WHERE ARRAY_CONTAINS(c.tags, "B")
将 return 文档 "one"。
如何查询包含数组中可能值列表的文档?
Return 标签数组中至少有一个值为 IN("B", "C").
的所有文档
-> 文档 "one" 和 "two"
您可以将 JOIN
运算符与 IN
运算符结合使用,该运算符用于与嵌套数组元素形成叉积。
SELECT docs
FROM docs
JOIN tags IN docs.tags
WHERE tags IN ("B", "C")
请注意,由于您创建的是叉积,因此您将获得每个匹配子元素的结果,而不是每个文档的结果。
或者,您可以将多个 ARRAY_CONTAINS
与 OR
运算符结合起来,或者编写一个 UDF。
我已经设法通过 Andrew Liu 建议的用户定义函数找到了解决方案,因为 - 正如他提到的 - 这种 JOIN
方法返回叉积,因此每个匹配项都会作为结果给出。
在我的例子中,我需要确定用户是否有权查看文档 - 它是通过组分配到达的。每个用户都有他的组列表,每个文档都有一个允许查看其内容的组列表。
对于所描述的示例,假设我们有一个允许分组 ["g1"、"g2"、"g3"] 的文档和一个可以在分组 [[=] 中查看文档的用户30=],"g3"].
使用我们的SQL JOIN
方法,当我们查找可用文档时,上述文档将被返回两次。如果 Distinct 函数可用于 DocumentDB,也许我不会关心这个,但目前它不是(但你仍然可以 vote 它)。
UDF 是使用 javascript 定义的,因此负责确定两个列表(数组)是否具有公共元素的代码如下所示:
function(array1, array2) {
return array1.some(function (v) {
return array2.indexOf(v) >= 0;
});
}
要从 C# 代码定义此类脚本,您可以遵循以下代码段:
UserDefinedFunction udf =
_client.CreateUserDefinedFunctionQuery(_collection.UserDefinedFunctionsLink)
.Where(x => x.Id == "ArraysHasCommonElem")
.AsEnumerable()
.FirstOrDefault();
if (udf == null)
{
udf = new UserDefinedFunction
{
Body = @"function(array1, array2) {
return array1.some(function (v) {
return array2.indexOf(v) >= 0;
});
}",
Id = "ArraysHasCommonElem"
};
await _client.CreateUserDefinedFunctionAsync(collectionUri.SelfLink, udf);
}
最后 运行 工作 SQL 查询记住每个用户定义函数调用之前需要的 'udf' 前缀:
SELECT * FROM docs
WHERE udf.ArraysHasCommonElem(your_array1, your_array2)
我有包含简单(字符串)数组的文档 属性。
{
"id": "one",
"tags": ["A", "B"]
}
{
"id": "two",
"tags": ["A", "C"]
}
要检查某个值是否是数组的一部分,我可以使用 ARRAY_CONTAINS
SELECT * FROM c WHERE ARRAY_CONTAINS(c.tags, "B")
将 return 文档 "one"。
如何查询包含数组中可能值列表的文档?
Return 标签数组中至少有一个值为 IN("B", "C").
的所有文档
-> 文档 "one" 和 "two"
您可以将 JOIN
运算符与 IN
运算符结合使用,该运算符用于与嵌套数组元素形成叉积。
SELECT docs
FROM docs
JOIN tags IN docs.tags
WHERE tags IN ("B", "C")
请注意,由于您创建的是叉积,因此您将获得每个匹配子元素的结果,而不是每个文档的结果。
或者,您可以将多个 ARRAY_CONTAINS
与 OR
运算符结合起来,或者编写一个 UDF。
我已经设法通过 Andrew Liu 建议的用户定义函数找到了解决方案,因为 - 正如他提到的 - 这种 JOIN
方法返回叉积,因此每个匹配项都会作为结果给出。
在我的例子中,我需要确定用户是否有权查看文档 - 它是通过组分配到达的。每个用户都有他的组列表,每个文档都有一个允许查看其内容的组列表。
对于所描述的示例,假设我们有一个允许分组 ["g1"、"g2"、"g3"] 的文档和一个可以在分组 [[=] 中查看文档的用户30=],"g3"].
使用我们的SQL JOIN
方法,当我们查找可用文档时,上述文档将被返回两次。如果 Distinct 函数可用于 DocumentDB,也许我不会关心这个,但目前它不是(但你仍然可以 vote 它)。
UDF 是使用 javascript 定义的,因此负责确定两个列表(数组)是否具有公共元素的代码如下所示:
function(array1, array2) {
return array1.some(function (v) {
return array2.indexOf(v) >= 0;
});
}
要从 C# 代码定义此类脚本,您可以遵循以下代码段:
UserDefinedFunction udf =
_client.CreateUserDefinedFunctionQuery(_collection.UserDefinedFunctionsLink)
.Where(x => x.Id == "ArraysHasCommonElem")
.AsEnumerable()
.FirstOrDefault();
if (udf == null)
{
udf = new UserDefinedFunction
{
Body = @"function(array1, array2) {
return array1.some(function (v) {
return array2.indexOf(v) >= 0;
});
}",
Id = "ArraysHasCommonElem"
};
await _client.CreateUserDefinedFunctionAsync(collectionUri.SelfLink, udf);
}
最后 运行 工作 SQL 查询记住每个用户定义函数调用之前需要的 'udf' 前缀:
SELECT * FROM docs
WHERE udf.ArraysHasCommonElem(your_array1, your_array2)