Operations with Builders
On this page
Overview
In this guide, you can learn about the helper classes, or builders, that the .NET/C# Driver provides to create types used in your operations. Using builders helps you identify errors at compile time and avoid them at runtime. This guide provides information on builder classes that you can use for the following tasks:
Creating a filter definition
Creating a projection
Defining a sort order
Defining an update operation
Selecting index keys
Tip
MongoDB C# Analyzer
The MongoDB C# Analyzer is a tool that helps you analyze your builders definitions and understand how your .NET/C# code translates into the MongoDB Query API. For more information and installation instructions, see the MongoDB C# Analyzer reference page.
You should read this guide if you want to learn more about how to construct definitions and build up syntax using builders.
Sample Class
The code examples in this guide demonstrate how you can use builders to
create types to interact with documents in the sample collection plants.flowers
.
Documents in this collection are modeled by the following Flower
class:
public class Flower { public ObjectId Id { get; set; } public string Name { get; set; } public string Category { get; set; } public double Price { get; set; } public List<string> Season { get; set; } public double Stock { get; set; } public string Description { get; set; } }
Each builder class takes a generic type parameter
TDocument
which represents the type of document that you are working
with. In this guide, the Flower
class is the document type used in
each builder class example.
Construct a Filter
The FilterDefinitionBuilder
class provides a type-safe interface for
building up queries. Suppose you want to query your collection for
documents matching the following criteria:
Price
field value less than 20Category
field value is "Perennial"
Use builders to create the filter definition with the typed variant:
var builder = Builders<Flower>.Filter; var filter = builder.Lt(f => f.Price, 20) & builder.Eq(f => f.Category, "Perennial");
Using the typed variant form provides compile-time safety. Additionally, your IDE can provide refactoring support.
Alternatively, you can use string-based field names to contruct the filter:
var builder = Builders<Flower>.Filter; var filter = builder.Lt("Price", 20) & builder.Eq("Category", "Perennial");
Array Operators
If your document has properties or fields that serialize to arrays,
you can use the methods beginning with Any
, such as AnyEq()
or
AnyLt()
, to compare the entire array against a single item.
Use builders to check which documents in the collection have a
Season
array that includes "winter":
var builder = Builders<Flower>.Filter; var filter = builder.AnyEq(f => f.Season, "winter");
Create a Projection
The ProjectionDefinitionBuilder
class provides a type-safe interface for
defining a projection. Suppose you want to create a projection on the
Name
and Price
fields, but exclude the Id
field.
Use builders to create the projection definition with the typed variant:
var builder = Builders<Flower>.Projection; var projection = builder.Include(f => f.Name).Include(f => f.Price).Exclude(f => f.Id);
You can also use string-based field names to define the projection:
var builder = Builders<Flower>.Projection; var projection = builder.Include("Name").Include("Price").Exclude("Id");
Finally, you can use the Expression()
method to define the
projection:
var builder = Builders<Flower>.Projection; var projection = builder.Expression(f => new { Name = f.Name, Price = f.Price });
This definition has a return type of ProjectionDefinition<TDocument,
TProjection>
whereas the others return a
ProjectionDefinition<TDocument>
.
Lambda Expressions
The driver supports using lambda expressions to render projections. When
you define a Find()
projection with the Expression()
method to
create a lambda expression, the driver inspects the expression
to determine which fields are referenced and automatically constructs a
server-side projection to return only those fields.
You can also use lambda expressions to create new fields by performing
operations on values in your documents. The following example shows how
you can use a lambda expression to project a new Profit
field
using the Price
and Stock
fields:
var builder = Builders<Flower>.Projection; var projection = builder.Expression(f => new { Profit = f.Price * f.Stock });
Note
Id Field Exclusion
When you create a projection using a lambda expression, the output
automatically excludes the Id
field unless you explicitly include
is as a projection field.
Define a Sort
The SortDefinitionBuilder
class provides a type-safe interface for
building up sort syntax. Suppose you want to define a sort with the
following order:
Ascending on
Price
Descending on
Category
Use builders to create the sort definition with the typed variant:
var builder = Builders<Flower>.Sort; var sort = builder.Ascending(f => f.Price).Descending(f => f.Category);
Alternatively, you can use string-based field names to define the sort:
var builder = Builders<Flower>.Sort; var sort = builder.Ascending("Price").Descending("Category");
Define an Update
The UpdateDefinitionBuilder
class provides a type-safe interface for
building up an update specification. Suppose you want to create an
update specification with the following criteria:
Create the new field
SunRequirement
Multiply the
Price
field value by 0.9
Use builders to create the update specification with the typed variant:
var builder = Builders<Flower>.Update; var update = builder.Set(f => f.SunRequirement, "Full sun").Mul(f => f.Price, 0.9);
Alternatively, you can use string-based field names to define the update:
var builder = Builders<Flower>.Update; var update = builder.Set("SunRequirement", "Full sun").Mul("Price", 0.9);
Define Index Keys
The IndexKeysDefinitionBuilder
class provides a type-safe interface for
defining index keys. Suppose you want to select Category
as an
ascending index key.
Use builders to select the index key with the typed variant:
var builder = Builders<Flower>.IndexKeys; var keys = builder.Ascending(f => f.Category);
Alternatively, you can use string-based field names to select the index key:
var builder = Builders<BsonDocument>.IndexKeys; var keys = builder.Ascending("Category");
The IndexKeysDefinitionBuilder
class also provides methods to build
a wildcard index. You can create a wildcard index using All field paths
or A
single field path
, in this case using Category
:
var builder = Builders<Flower>.IndexKeys; var keys = builder.Wildcard();
var builder = Builders<Flower>.IndexKeys; // Using the typed variant var keys = builder.Wildcard(f => f.Category); // Using string-based field names var keys = builder.Wildcard("Category");
For more information about how to use wildcard indexes, see Wildcard Indexes.
Build an Aggregation Pipeline
The PipelineDefinitionBuilder
class provides a type-safe interface for
defining an aggregation pipeline. An aggregation pipeline is a series of
stages that are used to transform a document. Suppose you want to create a
pipeline that performs the following operations:
Matches all documents with "spring" in the
Season
fieldSorts the results by the
Category
fieldGroups the documents by category and shows the average price and total available for all documents in that category
Use PipelineDefinitionBuilder
classes to build the pipeline:
var sortBuilder = Builders<Flower>.Sort.Ascending(f => f.Category); var matchFilter = Builders<Flower>.Filter.AnyEq(f => f.Season, "spring"); var pipeline = new EmptyPipelineDefinition<Flower>() .Match(matchFilter) .Sort(sortBuilder) .Group(f => f.Category, g => new { name = g.Key, avgPrice = g.Average(f => f.Price), totalAvailable = g.Sum(f => f.Stock) } );
The preceding example creates the following pipeline:
[{ "$match" : { "season" : "spring" } }, { "$sort" : { "category" : 1 } }, { "$group" : { "_id" : "$category", "avgPrice" : { "$avg" : "$price" }, "totalAvailable" : { "$sum" : "$stock" } } }]
You can add stages to your pipeline that don't have corresponding type-safe
methods in the PipelineDefinitionBuilder
interface by providing your query
as a BsonDocument
to the AppendStage() method.
var pipeline = new EmptyPipelineDefinition<BsonDocument>().AppendStage<BsonDocument, BsonDocument, BsonDocument>("{ $set: { field1: '$field2' } }");
Note
When using a BsonDocument
to define your pipeline stage, the driver does
not take into account any BsonClassMap
, serialization attributes or
serialization conventions. The field names used in the BsonDocument
must
match those stored on the server.
For more information on providing a query as a BsonDocument
, see our
FAQ page.
To learn more about the Aggregation Pipeline, see the Aggregation Pipeline server manual page.
Build an Atlas Search Query
The Search
class provides a type-safe interface for creating a
$search
pipeline stage.
To learn how to construct search queries with the Search
class, see
Atlas Search.
Additional Information
Find runnable examples using builders for various operations under Usage Examples.
API Documentation
To learn more about any of the methods or types discussed in this guide, see the following API Documentation: