Tim Jarvis
Tim Jarvis

Reputation: 18815

dynamically building a Mongo Query using C# and the fluent library

I am trying to build up a mongo query, I very nearly have it working in Linq (95% there), but it looks like there is an unfortunate missing ability in the Linq provider to do the equivalent of an Intersect(coll).Any() or in Mongo parlance AnyIn()

I understand that if I use the fluent library with some builders I can build up a filter that will give me an AnyIn() - but what I am missing is how could I build up the whole query, the initial filter, the aggregation, projection and the filter at the end?

This is a very close approximation of my Linq query - this works exactly as required as long as I am not trying to compare collection membership in the filter

public List<MyResult> ListMyResults(Expression<Func<MyResult, bool>> filter, int skip, int take)
{
    // Limit to tennants on main Entity being queried
    var ents = ApplyDataRestrictions(db.GetCollection<Entity>("entities").AsQueryAble());
    var children = db.GetCollection<Child>("children").AsQueryable();
    var chickens = db.GetCollection<Chicken>("chickens").AsQueryable();

    // Join a couple collections for their counts
    var result = from ent in ents   
                join c in children on ent.Id equals c.EntityId into kids
                join ck in chickens on ent.Id equals ck.EntityId into birds
                // Project the results into a MyResult
                select new MyResult
                {
                    Id = ent.Id,
                    AProperty = ent.AProperty,
                    SomeCollection = ent.SomeCollection,
                    SomeOtherCollectionTagsMaybe = ent.SomeOtherCollectionTagsMaybe,
                    TotalKids = kids.Count(),
                    TotalChickens = birds.Count() 
                };
    if(filter != null)
    {
        // Apply the filter that was built up from criteria on the MyResults data shape
        result = result.Where(filter);
    }

    result = result.Skip(skip).Take(take);
    return result.ToList()
}

public IQueryable<Entity> ApplyDataRestrictions(IQueryable<Entity> query)
{
    ... restrict results to only those with my tennant id ...
}

Upvotes: 1

Views: 951

Answers (1)

mickl
mickl

Reputation: 49945

Actually it turns out that the same behavior can be achieved without Query Builder and AnyIn. Having IQueryable interface you can try .Any() with Contains() as inner predicate

var inMemoryList = new List<int>() { 3, 4, 5 };

var q = from doc in Col.AsQueryable()
        where doc.Collection.Any(x => inMemoryList.Contains(x))
        select doc;

or

var q2 = Col.AsQueryable().Where(x => x.Collection.Any(y => inMemoryList.Contains(y)));

Upvotes: 1

Related Questions