MongoDB projections limit the fields returned by a query. In the C# driver you have several ways to define them — from strongly-typed lambda expressions to lower-level field include/exclude builders. All approaches are valid; which one you choose depends on whether you need shape transformation or just field filtering.
Expression Projection via Builders
The most concise option — Builders<T>.Projection.Expression accepts a lambda that maps the document to any anonymous type or DTO. The driver translates the lambda into a MongoDB projection automatically:
// Builders.Projection.Expression — project to a target shape using a lambda
var collection = db.GetCollection<Person>("people");
var result = await collection
.Find(p => p.Age > 25)
.Project(Builders<Person>.Projection.Expression(
p => new { p.FirstName, p.LastName, p.Email }
))
.ToListAsync();FindExpressionProjectionDefinition
When you need to reuse the same projection or pass it around, FindExpressionProjectionDefinition<TDocument, TProjection> makes it a first-class object:
// FindExpressionProjectionDefinition — construct the projection explicitly
var projection = new FindExpressionProjectionDefinition<Person, PersonDto>(
p => new PersonDto
{
FullName = p.FirstName + " " + p.LastName,
Email = p.Email,
}
);
var result = await collection
.Find(p => p.Age > 25)
.Project(projection)
.ToListAsync();FindAsync with FindOptions
Pass the projection through FindOptions<TDocument, TProjection> when using the lower-level FindAsync overload. This is useful when you also need to control sort, limit, or skip in the same call:
// FindAsync with FindOptions — supply the projection as an option
var findOptions = new FindOptions<Person, PersonDto>
{
Projection = Builders<Person>.Projection.Expression(
p => new PersonDto
{
FullName = p.FirstName + " " + p.LastName,
Email = p.Email,
}
)
};
using var cursor = await collection.FindAsync(p => p.Age > 25, findOptions);
var result = await cursor.ToListAsync();Include / Exclude Projection
For field-level control without a DTO transformation, the Include / Exclude builder methods work similarly to the raw MongoDB projection syntax. _id is included by MongoDB unless explicitly excluded:
// Include / Exclude projection — field-level control (returns BsonDocument by default)
// Include only specific fields (1 = include, 0 = exclude)
var includeProjection = Builders<Person>.Projection
.Include(p => p.FirstName)
.Include(p => p.Email)
.Exclude(p => p.Id); // MongoDB includes _id by default; exclude explicitly if unwanted
var result = await collection
.Find(p => p.Age > 25)
.Project<PersonDto>(includeProjection)
.ToListAsync();