Skip to content

Commit c360f41

Browse files
Builders (#54)
1 parent dd3e31a commit c360f41

File tree

2 files changed

+401
-0
lines changed

2 files changed

+401
-0
lines changed

source/fundamentals/builders.txt

Lines changed: 352 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,352 @@
1+
.. _csharp-builders:
2+
3+
========================
4+
Operations with Builders
5+
========================
6+
7+
.. default-domain:: mongodb
8+
9+
.. contents:: On this page
10+
:local:
11+
:backlinks: none
12+
:depth: 2
13+
:class: singlecol
14+
15+
Overview
16+
--------
17+
18+
In this guide, you can learn about the helper classes, or **builders**, that
19+
the {+driver-short+} provides to create types used in your operations.
20+
Using builders helps you identify errors at compile time and avoid them
21+
at runtime. This guide provides information on builder classes that you
22+
can use for the following tasks:
23+
24+
- Creating a filter definition
25+
- Creating a projection
26+
- Defining a sort order
27+
- Defining an update operation
28+
- Selecting index keys
29+
30+
.. tip:: MongoDB Analyzer
31+
32+
The MongoDB Analyzer is a tool that helps you analyze your
33+
builders definitions and understand how your {+lang-framework+} code
34+
translates into the MongoDB Query API. For more information and
35+
installation instructions, see the `MongoDB Analyzer reference page <https://www.mongodb.com/docs/mongodb-analyzer/current/>`__.
36+
37+
You should read this guide if you want to learn more about how to
38+
construct definitions and build up syntax using builders.
39+
40+
Sample Class
41+
------------
42+
43+
The code examples in this guide demonstrate how you can use builders to
44+
create types to interact with documents in the sample collection ``plants.flowers``.
45+
Documents in this collection are modeled by the following ``Flower`` class:
46+
47+
.. literalinclude:: /includes/fundamentals/code-examples/builders.cs
48+
:language: csharp
49+
:dedent:
50+
:start-after: start-model
51+
:end-before: end-model
52+
53+
Each builder class takes a generic type parameter
54+
``TDocument`` which represents the type of document that you are working
55+
with. In this guide, the ``Flower`` class is the document type used in
56+
each builder class example.
57+
58+
Construct a Filter
59+
------------------
60+
61+
The ``FilterDefinitionBuilder`` class provides a type-safe interface for
62+
building up queries. Suppose you want to query your collection for
63+
documents matching the following criteria:
64+
65+
- ``Price`` field value less than 20
66+
- ``Category`` field value is "Perennial"
67+
68+
Use builders to create the filter definition with the typed variant:
69+
70+
.. code-block:: csharp
71+
:copyable: true
72+
73+
var builder = Builders<Flower>.Filter;
74+
var filter = builder.Lt(f => f.Price, 20) & builder.Eq(f => f.Category, "Perennial");
75+
76+
Using the typed variant form provides compile-time safety. Additionally,
77+
your IDE can provide refactoring support.
78+
79+
Alternatively, you can use string-based field names to contruct the filter:
80+
81+
.. code-block:: csharp
82+
:copyable: true
83+
84+
var builder = Builders<Flower>.Filter;
85+
var filter = builder.Lt("Price", 20) & builder.Eq("Category", "Perennial");
86+
87+
Array Operators
88+
~~~~~~~~~~~~~~~
89+
90+
If your document has properties or fields that serialize to arrays,
91+
you can use the methods beginning with ``Any``, such as ``AnyEq()`` or
92+
``AnyLt()``, to compare the entire array against a single item.
93+
94+
Use builders to check which documents in the collection have a
95+
``Season`` array that includes "winter":
96+
97+
.. code-block:: csharp
98+
:copyable: true
99+
100+
var builder = Builders<Flower>.Filter;
101+
var filter = builder.AnyEq(f => f.Season, "winter");
102+
103+
.. TODO for a complete list of expressions, see the Query page?
104+
105+
.. _csharp-builders-projection:
106+
107+
Create a Projection
108+
-------------------
109+
110+
The ``ProjectionDefinitionBuilder`` class provides a type-safe interface for
111+
defining a projection. Suppose you want to create a projection on the
112+
``Name`` and ``Price`` fields, but exclude the ``Id`` field.
113+
114+
Use builders to create the projection definition with the typed variant:
115+
116+
.. code-block:: csharp
117+
:copyable: true
118+
119+
var builder = Builders<Flower>.Projection;
120+
var projection = builder.Include(f => f.Name).Include(f => f.Price).Exclude(f => f.Id);
121+
122+
You can also use string-based field names to define the projection:
123+
124+
.. code-block:: csharp
125+
:copyable: true
126+
127+
var builder = Builders<Flower>.Projection;
128+
var projection = builder.Include("Name").Include("Price").Exclude("Id");
129+
130+
Finally, you can use the ``Expression()`` method to define the
131+
projection:
132+
133+
.. code-block:: csharp
134+
:copyable: true
135+
136+
var builder = Builders<Flower>.Projection;
137+
var projection = builder.Expression(f => new { Name = f.Name, Price = f.Price });
138+
139+
This definition has a return type of ``ProjectionDefinition<TDocument,
140+
TProjection>`` whereas the others return a
141+
``ProjectionDefinition<TDocument>``.
142+
143+
Lambda Expressions
144+
~~~~~~~~~~~~~~~~~~
145+
146+
The driver supports using lambda expressions to render projections. When
147+
you define a ``Find()`` projection with the ``Expression()`` method to
148+
create a lambda expression, the driver inspects the expression
149+
to determine which fields are referenced and automatically constructs a
150+
server-side projection to return only those fields.
151+
152+
You can also use lambda expressions to create new fields by performing
153+
operations on values in your documents. The following example shows how
154+
you can use a lambda expression to project a new ``Profit`` field
155+
using the ``Price`` and ``Stock`` fields:
156+
157+
.. code-block:: csharp
158+
:copyable: true
159+
160+
var builder = Builders<Flower>.Projection;
161+
var projection = builder.Expression(f => new { Profit = f.Price * f.Stock });
162+
163+
.. note:: ``Id`` Field Exclusion
164+
165+
When you create a projection using a lambda expression, the output
166+
automatically excludes the ``Id`` field unless you explicitly include
167+
is as a projection field.
168+
169+
Define a Sort
170+
-------------
171+
172+
The ``SortDefinitionBuilder`` class provides a type-safe interface for
173+
building up sort syntax. Suppose you want to define a sort with the
174+
following order:
175+
176+
- Ascending on ``Price``
177+
- Descending on ``Category``
178+
179+
Use builders to create the sort definition with the typed variant:
180+
181+
.. code-block:: csharp
182+
:copyable: true
183+
184+
var builder = Builders<Flower>.Sort;
185+
var sort = builder.Ascending(f => f.Price).Descending(f => f.Category);
186+
187+
Alternatively, you can use string-based field names to define the sort:
188+
189+
.. code-block:: csharp
190+
:copyable: true
191+
192+
var builder = Builders<Flower>.Sort;
193+
var sort = builder.Ascending("Price").Descending("Category");
194+
195+
Define an Update
196+
----------------
197+
198+
The ``UpdateDefinitionBuilder`` class provides a type-safe interface for
199+
building up an update specification. Suppose you want to create an
200+
update specification with the following criteria:
201+
202+
- Create the new field ``SunRequirement``
203+
- Multiply the ``Price`` field value by 0.9
204+
205+
Use builders to create the update specification with the typed variant:
206+
207+
.. code-block:: csharp
208+
:copyable: true
209+
210+
var builder = Builders<Flower>.Update;
211+
var update = builder.Set(f => f.SunRequirement, "Full sun").Mul(f => f.Price, 0.9);
212+
213+
Alternatively, you can use string-based field names to define the update:
214+
215+
.. code-block:: csharp
216+
:copyable: true
217+
218+
var builder = Builders<Flower>.Update;
219+
var update = builder.Set("SunRequirement", "Full sun").Mul("Price", 0.9);
220+
221+
.. _csharp-builders-indexes:
222+
223+
Define Index Keys
224+
-----------------
225+
226+
The ``IndexKeysDefinitionBuilder`` class provides a type-safe interface for
227+
defining index keys. Suppose you want to select ``Category`` as an
228+
ascending index key.
229+
230+
Use builders to select the index key with the typed variant:
231+
232+
.. code-block:: csharp
233+
:copyable: true
234+
235+
var builder = Builders<Flower>.IndexKeys;
236+
var keys = builder.Ascending(f => f.Category);
237+
238+
Alternatively, you can use string-based field names to select the index key:
239+
240+
.. code-block:: csharp
241+
:copyable: true
242+
243+
var builder = Builders<BsonDocument>.IndexKeys;
244+
var keys = builder.Ascending("Category");
245+
246+
The ``IndexKeysDefinitionBuilder`` class also provides methods to build
247+
a wildcard index. You can create a wildcard index using ``All field paths`` or ``A
248+
single field path``, in this case using ``Category``:
249+
250+
.. tabs::
251+
252+
.. tab:: ``All field paths``
253+
:tabid: all-wildcard-index
254+
255+
.. code-block:: csharp
256+
:copyable: true
257+
258+
var builder = Builders<Flower>.IndexKeys;
259+
var keys = builder.Wildcard();
260+
261+
.. tab:: ``A single field path``
262+
:tabid: single-wildcard-index
263+
264+
.. code-block:: csharp
265+
:copyable: true
266+
267+
var builder = Builders<Flower>.IndexKeys;
268+
269+
// Using the typed variant
270+
var keys = builder.Wildcard(f => f.Category);
271+
272+
// Using string-based field names
273+
var keys = builder.Wildcard("Category");
274+
275+
Build an Aggregation Pipeline
276+
-----------------------------
277+
278+
The ``PipelineDefinitionBuilder`` class provides a type-safe interface for
279+
defining an **aggregation pipeline**. An aggregation pipeline is a series of
280+
stages that are used to transform a document. Suppose you want to create a
281+
pipeline that performs the following operations:
282+
283+
- Matches all documents with "spring" in the ``Season`` field
284+
- Sorts the results by the ``Category`` field
285+
- Groups the documents by category and shows the average price and total
286+
available for all documents in that category
287+
288+
Use ``PipelineDefinitionBuilder`` classes to build the pipeline:
289+
290+
.. code-block:: csharp
291+
292+
var sortBuilder = Builders<Flower>.Sort.Ascending(f => f.Category);
293+
var matchFilter = Builders<Flower>.Filter.AnyEq(f => f.Season, "spring");
294+
295+
var pipeline = new EmptyPipelineDefinition<Flower>()
296+
.Match(matchFilter)
297+
.Sort(sortBuilder)
298+
.Group(f => f.Category,
299+
g => new
300+
{
301+
name = g.Key,
302+
avgPrice = g.Average(f => f.Price),
303+
totalAvailable = g.Sum(f => f.Stock)
304+
}
305+
);
306+
307+
The preceding example creates the following pipeline:
308+
309+
.. code-block:: json
310+
311+
[{ "$match" : { "season" : "spring" } }, { "$sort" : { "category" : 1 } }, { "$group" : { "_id" : "$category", "avgPrice" : { "$avg" : "$price" }, "totalAvailable" : { "$sum" : "$stock" } } }]
312+
313+
You can add stages to your pipeline that don't have corresponding type-safe
314+
methods in the ``PipelineDefinitionBuilder`` interface by providing your query
315+
as a ``BsonDocument`` to the `AppendStage() method
316+
<{+api-root+}/M_MongoDB_Driver_PipelineDefinitionBuilder_AppendStage__3.htm>`__.
317+
318+
.. code-block:: csharp
319+
320+
var pipeline = new EmptyPipelineDefinition<BsonDocument>().AppendStage<BsonDocument, BsonDocument, BsonDocument>("{ $set: { field1: '$field2' } }");
321+
322+
.. note::
323+
324+
When using a ``BsonDocument`` to define your pipeline stage, the driver does
325+
not take into account any ``BsonClassMap``, serialization attributes or
326+
serialization conventions. The field names used in the ``BsonDocument`` must
327+
match those stored on the server.
328+
329+
For more information on providing a query as a ``BsonDocument``, see our
330+
:ref:`FAQ page <csharp-faq-unsupported-expressions>`.
331+
332+
To learn more about the Aggregation Pipeline, see the
333+
:manual:`Aggregation Pipeline </core/aggregation-pipeline/>` server manual page.
334+
335+
Additional Information
336+
----------------------
337+
338+
Find runnable examples using builders for various operations under
339+
:ref:`Usage Examples <csharp-usage-examples>`.
340+
341+
API Documentation
342+
~~~~~~~~~~~~~~~~~
343+
344+
To learn more about any of the methods or types discussed in this
345+
guide, see the following API Documentation:
346+
347+
- `FilterDefinitionBuilder <{+api-root+}/T_MongoDB_Driver_FilterDefinitionBuilder_1.htm>`__
348+
- `ProjectionDefinitionBuilder <{+api-root+}/T_MongoDB_Driver_ProjectionDefinitionBuilder_1.htm>`__
349+
- `SortDefinitionBuilder <{+api-root+}/T_MongoDB_Driver_SortDefinitionBuilder_1.htm>`__
350+
- `UpdateDefinitionBuilder <{+api-root+}/T_MongoDB_Driver_UpdateDefinitionBuilder_1.htm>`__
351+
- `IndexKeysDefinitionBuilder <{+api-root+}/T_MongoDB_Driver_IndexKeysDefinitionBuilder_1.htm>`__
352+
- `IndexKeysDefinitionBuilder <{+api-root+}/T_MongoDB_Driver_PipelineDefinitionBuilder.htm>`__

0 commit comments

Comments
 (0)