Skip to content

Commit 94b59f1

Browse files
authored
DOCSP 24553: Builders Page (#29)
* DOCSP-24553 builders fundamentals pg * first draft with all sections * various fixes * PR comments 1
1 parent e57ef2a commit 94b59f1

File tree

3 files changed

+337
-1
lines changed

3 files changed

+337
-1
lines changed

source/fundamentals.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,5 @@ Fundamentals
1111
:maxdepth: 1
1212

1313
/fundamentals/connection
14-
/fundamentals/crud
14+
/fundamentals/crud
15+
/fundamentals/builders

source/fundamentals/builders.txt

Lines changed: 287 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,287 @@
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+
Create a Projection
106+
-------------------
107+
108+
The ``ProjectionDefinitionBuilder`` class provides a type-safe interface for
109+
defining a projection. Suppose you want to create a projection on the
110+
``Name`` and ``Price`` fields, but exclude the ``Id`` field.
111+
112+
Use builders to create the projection definition with the typed variant:
113+
114+
.. code-block:: csharp
115+
:copyable: true
116+
117+
var builder = Builders<Flower>.Projection;
118+
var projection = builder.Include(f => f.Name).Include(f => f.Price).Exclude(f => f.Id);
119+
120+
You can also use string-based field names to define the projection:
121+
122+
.. code-block:: csharp
123+
:copyable: true
124+
125+
var builder = Builders<Flower>.Projection;
126+
var projection = builder.Include("Name").Include("Price").Exclude("Id");
127+
128+
Finally, you can use the ``Expression()`` method to define the
129+
projection:
130+
131+
.. code-block:: csharp
132+
:copyable: true
133+
134+
var builder = Builders<Flower>.Projection;
135+
var projection = builder.Expression(f => new { Name = f.Name, Price = f.Price });
136+
137+
This definition has a return type of ``ProjectionDefinition<TDocument,
138+
TProjection>`` whereas the others return a
139+
``ProjectionDefinition<TDocument>``.
140+
141+
Lambda Expressions
142+
~~~~~~~~~~~~~~~~~~
143+
144+
The driver supports using lambda expressions to render projections. When
145+
you define a ``Find()`` projection with the ``Expression()`` method to
146+
create a lambda expression, the driver inspects the expression
147+
to determine which fields are referenced and automatically constructs a
148+
server-side projection to return only those fields.
149+
150+
You can also use lambda expressions to create new fields by performing
151+
operations on values in your documents. The following example shows how
152+
you can use a lambda expression to project a new ``Profit`` field
153+
using the ``Price`` and ``Stock`` fields:
154+
155+
.. code-block:: csharp
156+
:copyable: true
157+
158+
var builder = Builders<Flower>.Projection;
159+
var projection = builder.Expression(f => new { Profit = f.Price * f.Stock });
160+
161+
.. note:: ``Id`` Field Exclusion
162+
163+
When you create a projection using a lambda expression, the output
164+
automatically excludes the ``Id`` field unless you explicitly include
165+
is as a projection field.
166+
167+
Define a Sort
168+
-------------
169+
170+
The ``SortDefinitionBuilder`` class provides a type-safe interface for
171+
building up sort syntax. Suppose you want to define a sort with the
172+
following order:
173+
174+
- Ascending on ``Price``
175+
- Descending on ``Category``
176+
177+
Use builders to create the sort definition with the typed variant:
178+
179+
.. code-block:: csharp
180+
:copyable: true
181+
182+
var builder = Builders<Flower>.Sort;
183+
var sort = builder.Ascending(f => f.Price).Descending(f => f.Category);
184+
185+
Alternatively, you can use string-based field names to define the sort:
186+
187+
.. code-block:: csharp
188+
:copyable: true
189+
190+
var builder = Builders<Flower>.Sort;
191+
var sort = builder.Ascending("Price").Descending("Category");
192+
193+
Define an Update
194+
----------------
195+
196+
The ``UpdateDefinitionBuilder`` class provides a type-safe interface for
197+
building up an update specification. Suppose you want to create an
198+
update specification with the following criteria:
199+
200+
- Create the new field ``SunRequirement``
201+
- Multiply the ``Price`` field value by 0.9
202+
203+
Use builders to create the update specification with the typed variant:
204+
205+
.. code-block:: csharp
206+
:copyable: true
207+
208+
var builder = Builders<Flower>.Update;
209+
var update = builder.Set(f => f.SunRequirement, "Full sun").Mul(f => f.Price, 0.9);
210+
211+
Alternatively, you can use string-based field names to define the update:
212+
213+
.. code-block:: csharp
214+
:copyable: true
215+
216+
var builder = Builders<Flower>.Update;
217+
var update = builder.Set("SunRequirement", "Full sun").Mul("Price", 0.9);
218+
219+
Define Index Keys
220+
-----------------
221+
222+
The ``IndexKeysDefinitionBuilder`` class provides a type-safe interface for
223+
defining index keys. Suppose you want to select ``Category`` as an
224+
ascending index key.
225+
226+
Use builders to select the index key with the typed variant:
227+
228+
.. code-block:: csharp
229+
:copyable: true
230+
231+
var builder = Builders<Flower>.IndexKeys;
232+
var keys = builder.Ascending(f => f.Category);
233+
234+
Alternatively, you can use string-based field names to select the index key:
235+
236+
.. code-block:: csharp
237+
:copyable: true
238+
239+
var builder = Builders<BsonDocument>.IndexKeys;
240+
var keys = builder.Ascending("Category");
241+
242+
The ``IndexKeysDefinitionBuilder`` class also provides methods to build
243+
a wildcard index. You can create a wildcard index using ``All field paths`` or ``A
244+
single field path``, in this case using ``Category``:
245+
246+
.. tabs::
247+
248+
.. tab:: ``All field paths``
249+
:tabid: all-wildcard-index
250+
251+
.. code-block:: csharp
252+
:copyable: true
253+
254+
var builder = Builders<Flower>.IndexKeys;
255+
var keys = builder.Wildcard();
256+
257+
.. tab:: ``A single field path``
258+
:tabid: single-wildcard-index
259+
260+
.. code-block:: csharp
261+
:copyable: true
262+
263+
var builder = Builders<Flower>.IndexKeys;
264+
265+
// Using the typed variant
266+
var keys = builder.Wildcard(f => f.Category);
267+
268+
// Using string-based field names
269+
var keys = builder.Wildcard("Category");
270+
271+
Additional Information
272+
----------------------
273+
274+
Find runnable examples using builders for various operations under
275+
:ref:`Usage Examples <csharp-usage-examples>`.
276+
277+
API Documentation
278+
~~~~~~~~~~~~~~~~~
279+
280+
To learn more about any of the methods or types discussed in this
281+
guide, see the following API Documentation:
282+
283+
- `FilterDefinitionBuilder <{+api-root+}/T_MongoDB_Driver_FilterDefinitionBuilder_1.htm>`__
284+
- `ProjectionDefinitionBuilder <{+api-root+}/T_MongoDB_Driver_ProjectionDefinitionBuilder_1.htm>`__
285+
- `SortDefinitionBuilder <{+api-root+}/T_MongoDB_Driver_SortDefinitionBuilder_1.htm>`__
286+
- `UpdateDefinitionBuilder <{+api-root+}/T_MongoDB_Driver_UpdateDefinitionBuilder_1.htm>`__
287+
- `IndexKeysDefinitionBuilder <{+api-root+}/T_MongoDB_Driver_IndexKeysDefinitionBuilder_1.htm>`__
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
using MongoDB.Driver;
2+
using static System.Console;
3+
using MongoDB.Bson;
4+
5+
namespace TestRun.Fundamentals;
6+
7+
public class Builders
8+
{
9+
private static IMongoCollection<Flower> _flowerCollection;
10+
private static string _mongoConnectionString = "<Your MongoDB URI>";
11+
12+
public static void Main(string[] args)
13+
{
14+
Setup();
15+
16+
// Sample builders definitions
17+
var filter = Builders<Flower>.Filter.AnyEq(flower => flower.Season, "spring");
18+
var projection = Builders<Flower>.Projection.Include("Name").Include("Price").Exclude("Id");
19+
var sort = Builders<Flower>.Sort.Ascending("Price").Descending("Category");
20+
21+
WriteLine("Finding documents...");
22+
var result = _flowerCollection.Find(filter).Sort(sort).Project(projection).toList();
23+
24+
WriteLine(result.ToJson());
25+
26+
var update = Builders<Flower>.Update.Mul("Price", 0.9);
27+
var result2 = _flowerCollection.UpdateOne(filter, update);
28+
}
29+
private static void Setup()
30+
{
31+
// Establish the connection to MongoDB and get the restaurants database
32+
var mongoClient = new MongoClient(_mongoConnectionString);
33+
var myDatabase = mongoClient.GetDatabase("plants");
34+
_flowerCollection = myDatabase.GetCollection<Flower>("flowers");
35+
}
36+
}
37+
38+
// start-model
39+
public class Flower
40+
{
41+
public ObjectId Id { get; set; }
42+
public string Name { get; set; }
43+
public string Category { get; set; }
44+
public double Price { get; set; }
45+
public List<string> Season { get; set; }
46+
public double Stock { get; set; }
47+
}
48+
// end-model

0 commit comments

Comments
 (0)