C# MongoDB 驱动程序:无法在 MongoDB 中找到 运行 AnyIn 过滤器的复杂查询方式
C# MongoDB Driver: Can't find the way to run complex query for AnyIn filter in MongoDB
我有这样一个文档:
{
"id": "xxxxxxxxxxxx",
"groupsAuthorized": [
"USA/California/SF",
"France/IDF/Paris"
]
}
我有一个用户有一个授权组列表,例如:
"groups": [
"France/IDF",
"USA/NY/NYC"
]
我想要实现的是检索数据库中用户有权检索的所有文档,基本上我希望能够检查列表 "groupsAuthorized" 如果其中一个组包含我的用户授权
中包含的另一个列表 "groups" 的元素子集
使用以下值:
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"
]
它不应该工作,因为我的用户只被授权查看来自 France/IDF/Paris 和 USA/NY/NYC 的文档,我文档的 authorizedGroups 中的字符串 none 包含这些序列
我尝试使用标准的 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# 驱动程序实现这一点有点无能为力,我开始认为我应该将所有文档拉到客户端并手动进行过滤,但那样会相当凌乱
有人对这个问题有想法吗?
i'm starting to think that I should just pull all documents to client and do the filtering manually but that would be quite messy
不要这样做 :)
您可以从 here 开始。它描述了 MongoDB .NET 驱动程序支持的所有 LINQ 运算符。如您所见,那里没有提到 .Contains()
,这意味着您不能使用它,并且您会在 运行 时间得到一个错误,但这并不意味着没有办法执行您的操作正在努力实现。
您可以使用的最接近 contains 的运算符是 $indexOfBytes which returns -1
if there's no match and the position of a substring otherwise. Also since you need to match an array against another array you need two pairs of $map and $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
class 来自 .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();
我有这样一个文档:
{
"id": "xxxxxxxxxxxx",
"groupsAuthorized": [
"USA/California/SF",
"France/IDF/Paris"
]
}
我有一个用户有一个授权组列表,例如:
"groups": [
"France/IDF",
"USA/NY/NYC"
]
我想要实现的是检索数据库中用户有权检索的所有文档,基本上我希望能够检查列表 "groupsAuthorized" 如果其中一个组包含我的用户授权
中包含的另一个列表 "groups" 的元素子集使用以下值:
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"
]
它不应该工作,因为我的用户只被授权查看来自 France/IDF/Paris 和 USA/NY/NYC 的文档,我文档的 authorizedGroups 中的字符串 none 包含这些序列
我尝试使用标准的 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# 驱动程序实现这一点有点无能为力,我开始认为我应该将所有文档拉到客户端并手动进行过滤,但那样会相当凌乱
有人对这个问题有想法吗?
i'm starting to think that I should just pull all documents to client and do the filtering manually but that would be quite messy
不要这样做 :)
您可以从 here 开始。它描述了 MongoDB .NET 驱动程序支持的所有 LINQ 运算符。如您所见,那里没有提到 .Contains()
,这意味着您不能使用它,并且您会在 运行 时间得到一个错误,但这并不意味着没有办法执行您的操作正在努力实现。
您可以使用的最接近 contains 的运算符是 $indexOfBytes which returns -1
if there's no match and the position of a substring otherwise. Also since you need to match an array against another array you need two pairs of $map and $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
class 来自 .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();