2017-10-28 167 views
0

我有一个名为some_collection的集合。为some_collection的模式是这样的:(该模式通过C#DTO决定)为不同类型的嵌套文档制作动态构建器过滤器 - MongoDB C#驱动程序

{ 
    _id: ObjectId(.....), 
    firstName: "fName", 
    lastName: "lName", 
    someType: 4, 
    innerObject: { 
     // see below 
    } 
} 

在我的C#代码,innerObject是一个抽象类,并有多个孩子的类。这些子类具有不同的属性,因此MongoDB集合中的文档不完全相同。他们所属的子类的类型由个人some_collection文档中的someType字段划定。所以,有2种不同类型的嵌套文档的audit_collection的2个文件的例子:

{ 
     _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" 
      } 
     ] 
    } 
} 

的应用案例这个问题,我想搜索用户提供的字符串,这样就可以在存在firstnamelastname属性(它位于文档的顶层,所有文档都很容易分享),以及对象的一些内部属性(因为嵌套的内部文档在模式上不同,所以它是更难做到)。因此,例如:

对于someType == 0,我会寻找myDocument.innerObject.aCollectionOfStrings,而与someType == 3,我搜索每个myDocument.innerObject.aCollectionOfObjectsmyProp财产。

在我的C#代码,如果我拉的全收集,然后用它LINQ操作,我有决定如何搜索完整的文档一个C#函数(基本上它检查的someType的值,然后基于此,它知道要搜索的属性)以及它的嵌套文档,并且可以在C#代码中进行过滤。

然而,重构用建设者的过滤器后,我无法通过,C#语言过滤功能进入过滤器(很明显,因为所有的生成器正在做的是建立一个MongoDB的查询,我认为):

filter = filter & Builders<MyOwnType>.Filter.Eq(a => CheckIfObjectHasString(a, search), true);

CheckIfObjectHasString是一样的东西:

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_collection文件属性,T帽子拥有所有可搜索的材料,但这似乎是不洁的。我如何构建像上面这样的过滤器,而不是在LINQ或我刚刚提到的解决方案中进行处理?

回答

0

我最终什么事做的是使原料BsonDocument比较的,比得上我一直在寻找,并$or荷兰国际集团他们,和嵌入在BsonDocuments$regex为各自的领域。我不知道在MongoDB中搜索文档时,如果不使用应用程序代码,您的查询就是一个要与之比较的文档。

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,我能够与使用我已有BuildersFilter小号例如为:

existingFilter = existingFilter | FindSearch(theSearch); // existingFilter is FilterDefinition<MyOwnType>

相关问题