Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Include/Exclude fields in query with MongoDB C# driver 2.4

We have a collection contains documents in the server. Each document is like:

{ _id: "...", Prop1: "", Prop2: "", Prop3: "", LargeField: "", ... }

There're many other fields but they're not required by the client.

I want to load documents as MyDoc class whose definition is:

public class MyDoc {
    public string Id { get; set; }
    public string Prop1 { get; set; }
    public string Prop2 { get; set; }
    public string Prop3 { get; set; }
    public string LargeField { get; set; }
}

I've tried:

var client = new MongoClient(uri);
var database = client.GetDatabase("MyDatabase");
var collection = database.GetCollection<MyDocs>("MyDocs");
var allDocs = collection.Find().ToList();

Then it will load all the fields for each document, so I have to put [BsonIgnoreExtraElements] on MyDoc. The issue here is that the document is large but I only needs a limit subset of fields. Is it possible to let the driver know I only need the fields defined in the class?

If not, is it possible to exclude some of the fields like the LargeField to make the result set smaller? I've tried:

var fieldsBuilder = Builders<MyDoc>.Projection;
var fields = fieldsBuilder.Exclude(d => d.LargeField);
var allDocs = collection.Find().Project(fields).ToList();

But now allDocs becomes BsonDocument list instead of the MyDoc list. How to query MyDoc with projection?

Can someone help? It's rather simple in legacy MongoDB driver but I don't know how to do it in the new driver. Thanks.

like image 638
Jeffrey Zhao Avatar asked Mar 20 '17 15:03

Jeffrey Zhao


2 Answers

I had a similar issue, I believe you need to specify the generic type, for some reason Project automatically assumes BsonDocument. This should fix it from BsonDocument to your class.

Change:

var allDocs = collection.Find().Project(fields).ToList();

To:

var allDocs = collection.Find<MyDoc>().Project<MyDoc>(fields).ToList();

As for how to include only certain fields, this can be done just as you are doing it with builder (using Include) or with a string in json form like:

var allDocs = collection.Find<MyDoc>().Project<MyDoc>("{Prop1: 1, Prop2: 1}").ToList();

I would highly recommend checking out projection on this guy's post: https://www.codementor.io/pmbanugo/working-with-mongodb-in-net-part-3-skip-sort-limit-and-projections-oqfwncyka

From this article:

This brings us to another difference: with a projection definition, it implicitly converts the document type from Student to BsonDocument, so what we get back is a fluent object that, in result, will be a BsonDocument (even though what we're working with is the Student type). If we want to work with Student, we have to indicate that we still want to keep the type to Student.

like image 129
Nate Avatar answered Oct 10 '22 06:10

Nate


A newer way:

var fieldsBuilder = Builders<MyDoc>.Projection;
var fields = fieldsBuilder.Exclude(d => d.BigField1).Exclude(d => d.BigField2);

return Collection.Find(x => x.id.Equals(id)).Project<MyDoc>(fields).ToEnumerable();

Gina

like image 41
Gina Marano Avatar answered Oct 10 '22 04:10

Gina Marano