How can I 'AND' multiple $elemMatch clauses with C# and MongoDB?

倾然丶 夕夏残阳落幕 提交于 2019-11-29 07:03:12
Andrew Orsich

There is no way to build above query using c# driver (at least in version 1.0).

But you can build another, more clear query, that will return same result:

{ "Relationships" : 
          { "$elemMatch" : 
              { "RelationshipType" : "Test", 
                "Attributes.Institution" : { "$all" : ["Location1", "Location2"] } 
              } 
          } 
}

And the same query from c#:

Query.ElemMatch("Relationships", 
    Query.And(
        Query.EQ("RelationshipType", "Test"),
            Query.All("Attributes.Institution", "Location1", "Location2")));

A simple solution is to string together multiple IMongoQuery(s) and then join them with a Query.And at the end:

List<IMongoQuery> build = new List<IMongoQuery>();
build.Add(Query.ElemMatch("Relationships", Query.EQ("RelationshipType", "Person")));

var searchQuery =  String.Format("/.*{0}.*/", "sta");
build.Add(Query.ElemMatch("Relationships", Query.Or(Query.EQ("Attributes.FirstName", new BsonRegularExpression(searchQuery)), Query.EQ("Attributes.LastName", new BsonRegularExpression(searchQuery)))));

var _main = Query.And(build.ToArray());

var DB = MongoDatabase.Create("UrlToMongoDB");
DB.GetCollection<ObjectToQuery>("nameOfCollectionInMongoDB").FindAs<ObjectToQuery>(_main).ToList();

`

Travis Stafford

I have solved the immediate issue by contruction a set of class that allowed for the generation of the following query:

{  'Relationships': 
    { 
        $all: [
         {$elemMatch: {'RelationshipType':'Student', 'Attributes.Institution': 'Test1'}},            
         {$elemMatch: {'RelationshipType':'Staff',   'Attributes.Institution': 'Test2'}}     
        ]
    }
}

Here are the class definitions:

class MongoQueryAll
    {
        public string Name { get; set; }
        public List<MongoQueryElement> QueryElements { get; set; }

        public MongoQueryAll(string name)
       {
           Name = name;
           QueryElements = new List<MongoQueryElement>();
       }

       public override string ToString()
       {
           string qelems = "";
           foreach (var qe in QueryElements)
              qelems = qelems + qe + ",";

           string query = String.Format(@"{{ ""{0}"" : {{ $all : [ {1} ] }} }}", this.Name, qelems); 

           return query;
       }
  }

class MongoQueryElement
{
    public List<MongoQueryPredicate> QueryPredicates { get; set; }

    public MongoQueryElement()
    {
        QueryPredicates = new List<MongoQueryPredicate>();
    }

    public override string ToString()
    {
        string predicates = "";
        foreach (var qp in QueryPredicates)
        {
            predicates = predicates + qp.ToString() + ",";
        }

        return String.Format(@"{{ ""$elemMatch"" : {{ {0} }} }}", predicates);
    }
}

class MongoQueryPredicate
{        
    public string Name { get; set; }
    public object Value { get; set; }

    public MongoQueryPredicate(string name, object value)
    {
        Name = name;
        Value = value;
    }

    public override string ToString()
    {
        if (this.Value is int)
            return String.Format(@" ""{0}"" : {1} ", this.Name, this.Value);

        return String.Format(@" ""{0}"" : ""{1}"" ", this.Name, this.Value);
    }
}

Helper Search Class:

public class IdentityAttributeSearch
{
    public string Name { get; set; }
    public object Datum { get; set; }
    public string RelationshipType { get; set; }
}

Example Usage:

 public List<IIdentity> FindIdentities(List<IdentityAttributeSearch> searchAttributes)
 {
        var server = MongoServer.Create("mongodb://localhost/");
        var db = server.GetDatabase("IdentityManager");
        var collection = db.GetCollection<MongoIdentity>("Identities");

        MongoQueryAll qAll = new MongoQueryAll("Relationships");

        foreach (var search in searchAttributes)
        {
            MongoQueryElement qE = new MongoQueryElement();
            qE.QueryPredicates.Add(new MongoQueryPredicate("RelationshipType", search.RelationshipType));
            qE.QueryPredicates.Add(new MongoQueryPredicate("Attributes." + search.Name, search.Datum));
            qAll.QueryElements.Add(qE);
        }

        BsonDocument doc = MongoDB.Bson.Serialization
                .BsonSerializer.Deserialize<BsonDocument>(qAll.ToString());

        var identities = collection.Find(new QueryComplete(doc)).ToList();

        return identities;
    }

I am sure there is a much better way but this worked for now and appears to be flexible enough for my needs. All suggestions are welcome.

This is probably a separate question but for some reason this search can take up to 24 seconds on a document set of 100,000. I have tried adding various indexes but to no avail; any pointers in this regards would be fabulous.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!