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.