Introduction
The MongoDB driver does not support projection at the database level. For instance, if you perform a select
projection to an anonymous object, the database will return the entire object and perform the projection in memory. This can be extremely costly if the object is large.
The Code
To overcome this deficiency, we need to use a Mongo Cursor, pass the query parameters and define the properties that we want to return. The properties that we define will be projected on the database server and only they will be returned. The other properties on the object will revert to their
Below is a snippet of the repository code demonstrating the difference between the IQueryable
function and the function using the Mongo Cursor.
public IQueryable<T> All()
{
return this.Collection.AsQueryable();
}
public IEnumerable<T> Get(Expression<Func<T, bool>> criteria,
params Expression<Func<T, object>>[] fields)
{
return this.Collection.FindAs<T>(Query<T>.Where(criteria)).SetFields
(Fields<T>.Include(fields));
}
The queries will return the same annoymous obejct, the only differernce is where the projection occurs. The first query will perform the projection in-memory and the second query will perform the projection at the database level.
var example1 = _Repository.All().Where(a => a.value.TimeFrame == timeFrame &&
a.value.ResearchItem.Sector != null)
.Select(a => new { DisplayName = a.value.ResearchItem.Sector.DisplayName,
Name = a.value.ResearchItem.Sector.Name })
.ToList();
var example2 = _Repository.Get(a => a.value.TimeFrame == timeFrame &&
a.value.ResearchItem.Sector != null, a => a.value.ResearchItem.Sector)
.Select(a => new { DisplayName = a.value.ResearchItem.Sector.DisplayName,
Name = a.value.ResearchItem.Sector.Name })
.ToList();
Profiler Results
The IQueryable
produces the following result when looking at the MongoDB's profiler:

The Get
function, which uses the Mongo Curosr produces the following result:

The Get
function produces a much smaller response length of 17175
compared to the IQuerable
's response of 52404
.
Quote: MongoDB's Documention
system.profile.responseLength
The length in bytes of the operation’s result document. A large responseLength
can affect performance.
Conclusion
The implemention of the Get
function to your repositories can allow you to save bandwidth and memory. If you have any questions or comments, feel free to reach out. I also have a small piece of code which will perform the server side projection and return an IQueryable
allowing you to add additional logic such as sorting.