Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

MongoDB C# - DB Side Projection

0.00/5 (No votes)
7 Jan 2015 1  
MonogoDB server side projection using the C# driver

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.

C#
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.

C#
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:

Image 1

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

Image 2

The Get function produces a much smaller response length of 17175 compared to the IQuerable's response of 52404.

Quote: MongoDB's Documention

C#
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.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here