tsJensen

A quest for software excellence...

MongoDB C# Driver 2.0 AsQueryable Alternative

I’m a fan of LINQ and the IQueryable<T> interface power to compose dynamic queries based on input parameters. So when I needed to compose just such a query in a repository for a MongoDB collection, I found that the MongoDB C# 2.0.1 driver is currently missing the AsQueryable method which is slated for 2.1 release of the driver.

After a little searching, I found the Filter Definition Builder documentation and a happy alternative to building up or composing a query based on the presence of query parameters.

And here is a code sample:

public async Task<IEnumerable<MyData>> GetByQuery(MyDataQuery query)
{
    var filter = ComposeFilter(query);
    if (!query.Ascending)
    {
        var responses = await _invoiceCollection
            .Find(filter)
            .SortByDescending(x => x.TransactionDate)
            .Skip(query.Index)
            .Limit(query.Limit)
            .ToListAsync();
        return responses;
    }
    var ascResponses = await _invoiceCollection
        .Find(filter)
        .SortBy(x => x.TransactionDate)
        .Skip(query.Index)
        .Limit(query.Limit)
        .ToListAsync();
    return ascResponses;
}

private FilterDefinition<MyData> ComposeFilter(MyDataQuery query)
{
    var builder = Builders<MyData>.Filter;
    var filter = builder.Eq(x => x.CustomerId, query.CustomerId);
    if (query.StartDate.HasValue)
    {
        filter = filter & builder.Gte(x => x.TransactionDate, query.StartDate.Value);
    }

    if (query.EndDate.HasValue)
    {
        filter = filter & builder.Lt(x => x.TransactionDate, query.EndDate.Value);
    }

    if (query.InvoiceId != null)
    {
        filter = filter & builder.Eq(x => x.InvoiceID, query.InvoiceId);
    }

    if (query.ItemId != null)
    {
        filter = filter & builder.Eq(x => x.ItemID, query.ItemId);
    }
    return filter;
}

So now you have a dynamic query based on composition logic. Of course this is a very simple example and there are bound to be far more sophisticated ways of doing the same thing, but I found this one worked very well for me.