C# MongoDB 驱动程序:找不到在 MongoDB 中运行 AnyIn 过滤器的复杂查询的方法



我有这样的文档:

{
"id": "xxxxxxxxxxxx",
"groupsAuthorized": [
"USA/California/SF",
"France/IDF/Paris"
]
}

我有一个用户有一个授权组列表,例如:

"groups": [
"France/IDF",
"USA/NY/NYC"
]

我试图实现的是检索数据库中用户有权检索的所有文档,本质上,如果其中一个组包含我的用户授权中包含的其他列表"组"的元素的子集,则我希望能够签入"groupsAuthorized"列表

使用以下值:

my document:
{
"id": "xxxxxxxxxxxx",
"groupsAuthorized": [
"USA/California/SF",
"France/IDF/Paris"
]
}
my user permissions:
"groups": [
"France/IDF",
"USA/NY/NYC"
]

用户应该能够检索此文档,因为字符串"France/IDF"正确包含在字符串"France/IDF/Paris"中,但是,如果值如下所示:

my document:
{
"id": "xxxxxxxxxxxx",
"groupsAuthorized": [
"USA/California/SF",
"France/IDF"
]
}
my user permissions:
"groups": [
"France/IDF/Paris",
"USA/NY/NYC"
]

它应该不起作用,因为我的用户仅有权查看来自法国/IDF/巴黎和美国/纽约/纽约的文档,并且我的文档的授权组中的字符串都不包含这些序列

我尝试使用标准的 LINQ 查询来实现这一点,这相当简单:

var userAuthorizedGroups = new List<string> { "France/IDF/Paris", "USA/NY/NYC" };
var results = collection.AsQueryable()
.Where(entity => userAuthorizedGroups
.Any(userGroup => entity.authorizedGroups
.Any(entityAuthorizedGroup => entityAuthorizedGroup.Contains(userGroup))));

但是我遇到了著名的不受支持的过滤器异常,似乎很多人都有,我尝试了在互联网上找到的不同选项,如下所示:

var userAuthorizedGroups = new List<string> { "France/IDF/Paris", "USA/NY/NYC" };
var filter = Builders<PartitionedEntity<Passport>>.Filter.AnyIn(i => i.authorizedGroups, userAuthorizedGroups);
var results = (await collection.FindAsync(filter)).ToList();
return results;

但问题是这只会检查数组的一个元素是否包含在另一个数组中,它不适用于像"France/IDF"这样应该正确匹配"France/IDF/Paris"的情况,因为"France/IDF"字符串包含在我的文档内的"France/IDF/Paris"字符串中

我对如何使用mongodb C#驱动程序实现这一目标有点一无所知,我开始认为我应该将所有文档拉到客户端并手动进行过滤,但那会很混乱

有人对这个主题有想法吗?

我开始认为我应该将所有文档拉到客户端并手动进行过滤,但那会很混乱

不要这样做:)

您可以从这里开始的一个地方。它描述了MongoDB .NET驱动程序支持的所有LINQ运算符。如您所见.Contains()那里没有提到,这意味着您无法使用它,并且您将在运行时获得一个 arror,但这并不意味着没有办法实现您想要实现的目标。

您可以使用的最接近包含的运算符是 $indexOfBytes,如果没有匹配项,则返回-1,否则返回子字符串的位置。另外,由于您需要将一个数组与另一个数组匹配,因此您需要两对$map和$anyElementTrue来执行确切的操作。NET的.Any做到了。

您的查询(MongoDB客户端(可能如下所示:

db.collection.find({
$expr: {
$anyElementTrue: {
$map: {
input: "$groupsAuthorized",
as: "group",
in: {
$anyElementTrue: {
$map: { 
input: ["France/IDF/Paris", "USA/NY/NYC"],
as: "userGroup",
in: { $ne: [ -1, { $indexOfBytes: [ "$$userGroup", "$$group" ] } ] }
}
}
}
}
}
}
})

蒙戈游乐场,

可以使用BsonDocument类从 .NET 运行相同的查询,该类采用字符串 (JSON( 并转换为查询:

var query = BsonDocument.Parse(@"{
$expr: {
$anyElementTrue:
{
$map:
{
input: '$groupsAuthorized',
as: 'group',
in: {
$anyElementTrue:
{
$map:
{
input: ['France/IDF/Paris', 'USA/NY/NYC'],
as: 'userGroup',
in: { $ne: [-1, { $indexOfBytes: ['$$userGroup', '$$group'] } ] }
}
}
}
}
}
}
}");
var result = col.Find(query).ToList();

最新更新