Click here to Skip to main content
15,891,764 members
Articles / Database Development / MongoDB
Tip/Trick

MongoDB C# - DB Side Projection

Rate me:
Please Sign up or sign in to vote.
4.79/5 (6 votes)
7 Jan 2015CPOL1 min read 22.6K   11   2
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, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
QuestionWould be really nice if you stated what _Repository and this.Collection was. Pin
Member 813775821-Jan-18 13:31
Member 813775821-Jan-18 13:31 
GeneralMy vote of 5 Pin
Krys Everydev8-Jan-15 3:25
Krys Everydev8-Jan-15 3:25 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.