|
| 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