为不同类型的嵌套文档制作一个动态生成器过滤器-MongoDB C#Driver
我有一个名为为不同类型的嵌套文档制作一个动态生成器过滤器-MongoDB C#Driver,c#,mongodb,mongodb-query,filtering,C#,Mongodb,Mongodb Query,Filtering,我有一个名为some\u collection的收藏。some_collection的模式如下:(模式由C#DTO指定) 在我的C#代码中,innerObject是一个抽象类,有多个子类。这些子类具有不同的属性,因此MongoDB集合中的文档并不完全相同。它们所属的子类的类型由单个some\u集合文档中的someType字段划分。因此,audit_collection中包含两种不同类型嵌套文档的两个文档示例: { _id: ObjectId('first'),
some\u collection
的收藏。some_collection
的模式如下:(模式由C#DTO指定)
在我的C#代码中,innerObject是一个抽象类,有多个子类。这些子类具有不同的属性,因此MongoDB集合中的文档并不完全相同。它们所属的子类的类型由单个some\u集合
文档中的someType
字段划分。因此,audit_collection
中包含两种不同类型嵌套文档的两个文档示例:
{
_id: ObjectId('first'),
firstName: "Jane",
lastName: "Smith",
someType: 0,
innerObject: {
prop1: "foo",
prop2: "bar",
aCollectionOfStrings: ["a", "b", "c"] // this is what I wanna search
}
},
{
_id: ObjectId('second'),
firstName: "John",
lastName: "Doe",
someType: 3,
innerObject: {
prop1: "baz",
prop2: "foobarbaz",
aCollectionOfObjects: [
{
myProp: "hello", // this is what I want to search
irrelevantProp: "blah"
},
{
myProp: "hello5", // this is what I want to search
irrelevantProp: "blah"
},
{
myProp: "hello1", // this is what I want to search
irrelevantProp: "blah"
}
]
}
}
这个问题的用例是,我想搜索用户提供的字符串,它可以存在于firstname
和lastname
属性中(位于文档的顶层,所有文档共享它,非常简单),也可以存在于对象的一些内部属性中(由于嵌套的内部文档在架构中不同,因此更难实现)。例如:
对于someType==0
,我会搜索myDocument.innerObject.acollectionofstring
,而对于someType==3
,我会搜索每个myDocument.innerObject.aCollectionOfObjects
的myProp
属性
在我的C#代码中,如果我提取完整集合,然后对其使用LINQ操作,我有一个C#函数,它确定如何搜索完整文档(基本上它检查someType
的值,然后根据该值,它知道要搜索哪些属性),以及它的嵌套文档,并可以在C#代码中进行过滤
但是,在使用构建器过滤器进行重构之后,我无法将C#filter函数传递到过滤器中(显然,因为构建器所做的只是构建一个MongoDB查询,我认为):
filter=filter&Builders.filter.Eq(a=>checkifobjecthastring(a,search),true);
其中,CheckIfObjectHaString
类似于:
private bool CheckIfObjectHasString(MyOwnType doc, string search)
{
if(doc.someType == 0)
{
return doc.innerObject.aCollectionOfStrings.Where(s => s.ToLower().Contains(search)).Any();
} else if(doc.someType == 3) {
return doc.innerObject.aCollectionOfObjects.Where(d => d.myProp.ToLower().Contains(search)).Any();
} else if(...)
{
// etc.
}
}
我想到的一个解决方案是,在文档插入过程中,在最顶层的
some_集合
文档上创建一个属性,该属性包含所有可搜索的材料,但似乎不干净。我如何构建如上所述的过滤器,而不必使用LINQ或我刚才提到的解决方案进行处理d?我最终做的是使原始的BsonDocument
s与我正在寻找的内容相比较,并$or
将它们隐藏起来,并将$regex
嵌入BsonDocuments
中,用于各自的字段。我不知道在MongoDB中搜索文档时,在不使用应用程序代码的情况下,您的查询y是一个要比较的文档
private BsonDocument FindSearch(string searchString)
{
// escape the searchString
var filterDocument = new BsonDocument();
var searchDocument = new BsonDocument();
searchDocument.Add(("$regex", $".*{searchString}.*"));
searchDocument.Add("$options", "i"); // to ignore case when performing the regex
var searchCriterias = new BsonArray(); // an array because I'll be $or-ing it
searchCriterias.Add(new BsonDocument("innerObject.aCollectionOfObjects.myProp", textSearch)); // access each nested object's property
searchCriterias.Add(new BsonDocument("innerObject.aCollectionOfStrings", textSearch)); // even though it's an array of strings, I can just search without having to iterate them
filterDocument.Add("$or", searchCriterias); // $or-ing it also saved me from having to check the existence of properties, before doing the search
}
然后,即使它是一个BsonDocument
,我也能够将它与我已经存在的构建器
过滤器一起使用,例如:
existingFilter=existingFilter|FindSearch(theSearch);//existingFilter是filter定义
private BsonDocument FindSearch(string searchString)
{
// escape the searchString
var filterDocument = new BsonDocument();
var searchDocument = new BsonDocument();
searchDocument.Add(("$regex", $".*{searchString}.*"));
searchDocument.Add("$options", "i"); // to ignore case when performing the regex
var searchCriterias = new BsonArray(); // an array because I'll be $or-ing it
searchCriterias.Add(new BsonDocument("innerObject.aCollectionOfObjects.myProp", textSearch)); // access each nested object's property
searchCriterias.Add(new BsonDocument("innerObject.aCollectionOfStrings", textSearch)); // even though it's an array of strings, I can just search without having to iterate them
filterDocument.Add("$or", searchCriterias); // $or-ing it also saved me from having to check the existence of properties, before doing the search
}