Search code examples
c#jsonmongodbmongodb-querymongo-c-driver

MongoDB Create dynamic Query


Below is working code for 'And' Operation of Multiple Queries, I can able to do 'And' operation for list of Queries, 'Or' operation for list of Queries. But is there a way in MongoDB that i can do 'And' or 'Or' operation Dynamically for list of Queries?

public IQueryable<SocialRecord> GetWallSocialRecordsMongoQuery(Dictionary<string, List<string>> languagesPerTerms, string[] sources, DateTime fr, DateTime to)
        {
            try
            {
                var andList = new BindingList<IMongoQuery>
                    {
                        Query.And(Query<SocialRecord>.GTE(record => record.DateCreated, fr),
                                  Query<SocialRecord>.LTE(record => record.DateCreated, to),
                                  Query<SocialRecord>.In(record => record.SocialType, sources))
                    };

                foreach (var languagesPerTerm in languagesPerTerms)
                {
                    var term = languagesPerTerm;
                    andList.Add(Query.Or(Query.And((Query<SocialRecord>.Where(record => record.TermMonitorIds.Contains(term.Key))),
                              Query<SocialRecord>.In(record => record.Language, term.Value))));
                }
                return _collection.FindAs<SocialRecord>(Query.And(andList)).AsQueryable();
            }
            catch (Exception ex)
            {
                Log.Error("Exception in the Method GetWallSocialRecords, in the Class MongoSocialRecordRepository", ex);
            }

            return null;
        }

Document Structure

{
    "_id" : ObjectId("53a456b27f781d19f40ac76c"),
    "DateCreated" : ISODate("2014-06-20T15:35:56.000Z"),
    "SocialType" : "facebook",
    "RecordId" : "1474971936_10202431655820767",
    "UserId" : "1474971936",
    "UserProfileUrl" : "********",
    "UserProfilePictureUrl" : "/Downloads/v3/432bfeb8-901e-45a4-b739-1f3f48b69d61/facebook/2014-6/1946689/10492432_10202426005479512_740185019259071925_t.jpg",
    "Description" : "******",
    "MediaHiResUrl" : "",
    "MediaLowResUrl" : "",
    "MediaMedResUrl" : "",
    "SocialCount" : NumberLong(354),
    "SocialCountType" : "likes",
    "Sentiment" : "",
    "SentimentScore" : "0.0000000",
    "IsLocalContent" : true,
    "IsExactMatch" : true,
    "IsHashTag" : false,
    "IsActive" : false,
    "MediaType" : "image",
    "TermMonitorIds" : [ 
        "432bfeb8-901e-45a4-b739-1f3f48b69d61"
    ],
    "UserName" : "***",
    "DisplayName" : "",
    "DirectUrl" : "",
    "IsUk" : true,
    "IsEnglish" : true,
    "Language" : "en",
    "Location" : "GB",
    "DataVersion" : "v3"
}

Edit

I need to get below Query:

query {
    "DateCreated" : {
        "$gte" : ISODate("2015-02-02T16:55:37.979Z"),
        "$lte" : ISODate("2015-02-09T16:55:37.979Z")
    },
    "SocialType" : {
        "$in" : ["twitter"]
    },
    "$or" : [{
            "TermMonitorIds" : "b34b8bea-d1e6-4d05-bd25-5d07ad0b691e",
            "Language" : {
                "$in" : ["zh", "eo", "ja"]
            }
        }, {
            "TermMonitorIds" : "c8497f52-70dd-47b6-8abe-afac42c3a009",
            "Language" : {
                "$in" : ["zh", "eo", "ja"]
            }
        }
    ]
}

Any suggestions will be appreciated.


Solution

  • I found a way to do that, Might help anyone :

    public IQueryable<SocialRecord> GetWallSocialRecordsMongoQuery(Dictionary<string, List<string>> languagesPerTerms, string[] sources, DateTime fr, DateTime to)
            {
                try
                {
                    var list = new BindingList<IMongoQuery>();
    
                    foreach (var languagesPerTerm in languagesPerTerms)
                    {
                        var term = languagesPerTerm;
                        list.Add(!term.Value.Contains("All")
                                     ? Query.And(
                                         Query<SocialRecord>.Where(record => record.TermMonitorIds.Contains(term.Key)),
                                         Query<SocialRecord>.In(record => record.Language, term.Value))
                                     : Query<SocialRecord>.Where(record => record.TermMonitorIds.Contains(term.Key)));
                    }
    
                    var query = Query.And(Query<SocialRecord>.GTE(record => record.DateCreated, fr),
                                  Query<SocialRecord>.LTE(record => record.DateCreated, to),
                                  Query<SocialRecord>.In(record => record.SocialType, sources),
                                  Query.Or(list));
    
                    //var x = _collection.FindAs<SocialRecord>(query).Explain();
    
                    return _collection.FindAs<SocialRecord>(query).AsQueryable();
                }
                catch (Exception ex)
                {
                    Log.Error("Exception in the Method GetWallSocialRecords, in the Class MongoSocialRecordRepository", ex);
                }
    
                return null;
            }
    

    Please not that MongoDB Queries with the $or operator can use separate indexes on each clause of the $or expression.