Search code examples
c#.netmongodbmongodb-querymongodb-.net-driver

How to load specific fields from document(s) in C# Mongodb strongly typed driver


I am using the official C# MongoDb strongly typed driver version 2.5.0 to interact with MongoDB.

I have classes Book and Page as the following:

public class Book
{
    [BsonId]
    [BsonRepresentation(BsonType.ObjectId)]
    public string Id { get; set; }

    public string Title { get; set; }

    public string AuthorName { get; set; }

    public int PublishYear { get; set; }

    public List<Page> Pages { get; set; } = new List<Page>();

}


public class Page
{
    [BsonId]
    [BsonRepresentation(BsonType.ObjectId)]
    public string Id { get; set; }

    public int Number { get; set; }

    public string HTMLContent { get; set; }
}

My questions are:

1-How to query all books without the Pages field? Currently this is my code:

var repository = _database.GetCollection<Book>("Books");
List<Book> allBooks = await repository.Find(_ => true).ToListAsync();

2-How to get title, authorName and publishYear fields only without the pages field of a single book using the id field? Currently this is my code:

var repository = _database.GetCollection<Book>("Books");
var filter = Builders<Book>.Filter.Eq("Id", bookId);
Book book = await repository.Find(filter).FirstOrDefaultAsync();

3-How to get the pages field only of a single book as a List<Page> ? Currently this is my code:

var repository = _database.GetCollection<Book>("Books");
var filter = Builders<Book>.Filter.Eq("Id", bookId);
Book book = await repository.Find(filter).FirstOrDefaultAsync();
List<Page> pages = book != null ? book.Pages : new List<Page>();

Solution

  • You need Project operator. To exclude only specific fields you can do it like this:

    var allBooks = await repository.Find(_ => true)
        .Project<Book>(Builders<Book>.Projection.Exclude(c => c.Pages))
        .ToListAsync();
    

    To include only specific field:

     var allBooks = await repository.Find(_ => true)
        .Project<Book>(Builders<Book>.Projection.Include(c => c.Pages))
        .ToListAsync();
    

    If you need to include\exclude multiple fields - call that multiple times (Include(x => x.Title).Include(x => x.Title) etc).

    Alternative way to include only what you need:

    var allBooks = await repository.Find(_ => true).Project(b => new Book {
        AuthorName = b.AuthorName,
        Id = b.Id,
        PublishYear = b.PublishYear,
        Title = b.Title
        // specify what you need, don't specify what you do not
        // like Pages
    }).ToListAsync();