pedrommuller
pedrommuller

Reputation: 16056

MongoDB C# Select specific columns

I know that MongoDb C# driver doesn't support projections so I searched a little bit and I found that many people uses a mongoCursor to perform such queries, I'm trying to select only specific fields and my code is the following:

public T GetSingle<T>(Expression<Func<T, bool>> criteria,params Expression<Func<T, object>>[] fields) where T : class
{
    Collection = GetCollection<T>();
    return Collection.FindAs<T>(Query<T>.Where(criteria)).SetFields(Fields<T>.Include(fields)).SetLimit(1).SingleOrDefault();
} 

I got and custom repository for users on top of that:

public User GetByEmail(string mail, params Expression<Func<User, object>>[] fields)
{
    return GetSingle<User>(x=>x.Email==mail,fields);
}

this is the usage:

_repository.GetByEmail(email, x=>x.Id,x=>x.DisplayName,x=>x.ProfilePicture)

but I'm getting the fields included in the parameter but also all the Enums,dates and Boolean values that are part of the class User, the values that are string and not included in the field list are null so that's fine

enter image description here

what can I do to avoid that?

Upvotes: 1

Views: 3682

Answers (1)

mnemosyn
mnemosyn

Reputation: 46301

By using SetFields, you can specify what goes through the wire. However, you're still asking the driver to return hydrated objects of type T, User in this case.

Now, similar to say an int, enum and boolean are value types, so their value can't be null. So this is strictly a C#-problem: there is simply no value for these properties to indicate that they don't exist. Instead, they assume a default value (e.g. false for bool and 0 for numeric types). A string, on the other hand, is a reference type so it can be null.

Strategies

Make the properties nullable You can use nullable fields in your models, e.g.:

class User {
    public bool? GetMailNotifications { get; set; }
}

That way, the value type can have one of its valid values or be null. This can, however, be clumsy to work with because you'll have to do null checks and use myUser.GetMailNotifications.Value or the myUser.GetMailNotifications.GetValueOrDefault helper whenever you want to access the property.

Simply include the fields instead this doesn't answer the question of how to it, but there are at least three good reasons why it's a good idea to include them:

  1. When passing a User object around, it's desirable that the object is in a valid state. Otherwise, you might pass a partially hydrated object to a method which passes it further and at some point, someone attempts an operation that doesn't make sense because the object is incomplete
  2. It's easier to use
  3. The performance benefit is negligible, unless you're embedding huge arrays which I would suggest to refrain from anyway and which isn't the case here.

So the question is: why do you want to make all the effort of excluding certain fields?

Upvotes: 2

Related Questions