我正在尝试弄清楚如何使用 LinqToSql for cosmos db 执行此查询:
SELECT c FROM c
JOIN relation IN c.tagRelations
WHERE
c.tenantId = '<<tenant-id>>'
and c.IsDeleted = false
AND ARRAY_CONTAINS(c.tags, 'tag-id')
AND ARRAY_LENGTH(c.tagRelations)>= 0
AND relation.source = 'tag-id'
AND (
ARRAY_LENGTH(relation.target) != 2
OR ARRAY_LENGTH(SetIntersect(relation.target, ['related-1', 'related-2'])) != 2
)
在我们的代码中,我们无法直接编写此查询,因为 api 需要一个表达式
var tagId = "tag-id";
var RELATED_TAG_IDS = new []{"related-1", "related-2"};
var EXPECTED_NUMBER_OF_RELATED_TAGS = RELATED_TAG_IDS.Length;
var results = await db.Get<DatabaseDocument>(record
=> record.TenantId == "<<tenant-id>>"
&& record.IsDeleted == false
&& record.Tags.Contains(tagId)
&& record.TagRelations.Any(relation
=> relation.Source == tagId
&& (
relation.Target == null
|| relation.Target.Count() != EXPECTED_NUMBER_OF_RELATED_TAGS
|| relation.Target
.Select(relTag => RELATED_TAG_IDS.Contains(relTag))
.Count() != EXPECTED_NUMBER_OF_RELATED_TAGS
)
)
,
sorting => sorting.OrderByDescending(record => record.UploadTimestamp), ctoken);
如果数据库中的目标数量等于预期目标数量,并且有一个(或多个)值不同,则上述查询不会返回预期记录。
因此,如果有人可以解释如何使其正常工作,我将非常感激。
PS:据我所知,不可能使用 linq-to-sql 从 C# 内部调用 SetIntersect 函数。
PS:数据结构的示例应该是:
{
"tenantId": "<<tenant-id>>",
"IsDeleted": false,
"tags": ["tag-id", "tag-id-2", "tag-id-3"],
"tagRelations": [
{ "source": "tag-id", "target": ["tag-id-2", "tag-id-3"] },
{ "source": "tag-id-2", "target": ["tag-id-3"] }
{ "source": "tag-id-3", "target": [] }
],
...
}
PS:我需要做的是找到具有特定源标签和一组不正确的目标标签的所有记录。因此它可以没有目标,或多或少的目标,或者相同数量的目标但不同的值。
PS:我们使用nuget包“Microsoft.Azure.Cosmos”3.31.2。
Cosmos db - linq to sql - 查询在嵌套数组中包含所有输入参数的记录
我使用
GetItemLinqQueryable<>
在容器中创建 LINQ 可查询对象集合。通过使用它,我们可以使用 LINQ 表达式进行查询。一些表达式如下面var query
中的代码所示。它使用带有 &&
运算符的 where 子句来过滤数据。
我尝试过的代码:
public async Task<IEnumerable<DatabaseDocument>> ExecuteQueryAsync()
{
var tagId = "tag-id";
var RELATED_TAG_IDS = new[] { "related-1", "related-2" };
var EXPECTED_NUMBER_OF_RELATED_TAGS = RELATED_TAG_IDS.Length;
var query = container.GetItemLinqQueryable<DatabaseDocument>(allowSynchronousQueryExecution: true)
.Where(record =>
record.TenantId == "Tenant-1" &&
record.IsDeleted == false &&
record.Tags.Contains(tagId) &&
record.TagRelations.Any(relation =>
relation.Source == tagId &&
(relation.Target == null ||
relation.Target.Count() != EXPECTED_NUMBER_OF_RELATED_TAGS ||
relation.Target
.Where(relTag => RELATED_TAG_IDS.Contains(relTag))
.Count() != EXPECTED_NUMBER_OF_RELATED_TAGS)
)
);
var results = query.ToList();
return results;
}
SetIntersect 在 LINQ 中使用,同时从 Cosmos DB 容器中过滤文档。
relation.Target
表示 TagRelation
对象中相关标签的列表。
RELATED_TAG_IDS
是想要查找 Target
列表的相关标签数组。
Where
子句过滤 Target
列表,仅包含 RELATED_TAG_IDS
数组中的标签。它找到它们之间的交集。
示例输入:
{
"TenantId": "Tenant-1",
"IsDeleted": false,
"Tags": [
"tag-id",
"tag-id-2",
"tag-id-3"
],
"TagRelations": [
{
"Source": "tag-id",
"Target": [
"tag-id-2",
"tag-id-3"
]
},
{
"Source": "tag-id-2",
"Target": [
"tag-id-3"
]
},
{
"Source": "tag-id-3",
"Target": []
}
]
}
输出:
{ "TenantId": "Tenant-1", "Source": "tag-id", "Target": ["tag-id-2", "tag-id-3"] }