diff --git a/.github/workflows/check-autobuilder.yml b/.github/workflows/check-autobuilder.yml deleted file mode 100644 index 8495db96..00000000 --- a/.github/workflows/check-autobuilder.yml +++ /dev/null @@ -1,13 +0,0 @@ -name: Check Autobuilder for Errors - -on: - pull_request: - paths: - - "source/**" - -jobs: - check: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - uses: cbush/snooty-autobuilder-check@main diff --git a/.github/workflows/vale-tdbx.yml b/.github/workflows/vale-tdbx.yml index 8e4b6f49..d748e941 100644 --- a/.github/workflows/vale-tdbx.yml +++ b/.github/workflows/vale-tdbx.yml @@ -18,20 +18,20 @@ jobs: - id: files uses: masesgroup/retrieve-changed-files@v2 with: - format: 'csv' + format: "csv" - name: checkout-latest-rules uses: actions/checkout@master with: repository: mongodb/mongodb-vale-action - path: './tdbx-vale-rules' + path: "./tdbx-vale-rules" token: ${{secrets.GITHUB_TOKEN}} - name: move-files-for-vale-action run: | - cp tdbx-vale-rules/.vale.ini .vale.ini - mkdir -p .github/styles/ - cp -rf tdbx-vale-rules/.github/styles/ .github/ + cp tdbx-vale-rules/.vale.ini .vale.ini + mkdir -p .github/styles/ + cp -rf tdbx-vale-rules/.github/styles/ .github/ - name: run-vale uses: errata-ai/vale-action@reviewdog diff --git a/source/fundamentals/crud/write-operations.txt b/source/fundamentals/crud/write-operations.txt index 15b4b476..2a4bf5b9 100644 --- a/source/fundamentals/crud/write-operations.txt +++ b/source/fundamentals/crud/write-operations.txt @@ -15,6 +15,7 @@ Write Operations Update Many Replace Delete + Bulk Write - :ref:`csharp-insert-guide` - :ref:`csharp-update-one` @@ -22,3 +23,4 @@ Write Operations - :ref:`csharp-replace-documents` - :ref:`csharp-delete-guide` - :ref:`csharp-insert-guide` +- :ref:`csharp-bulk-write` diff --git a/source/fundamentals/crud/write-operations/bulk-write.txt b/source/fundamentals/crud/write-operations/bulk-write.txt new file mode 100644 index 00000000..b5e94466 --- /dev/null +++ b/source/fundamentals/crud/write-operations/bulk-write.txt @@ -0,0 +1,411 @@ +.. _csharp-bulk-write: + +===================== +Bulk Write Operations +===================== + +.. contents:: On this page + :local: + :backlinks: none + :depth: 2 + :class: singlecol + +.. facet:: + :name: genre + :values: reference + +.. meta:: + :keywords: insert, update, replace, code example, multiple changes + +Overview +-------- + +In this guide, you can learn how to use the {+driver-short+} to perform +**bulk write operations**. By using a bulk write operation, you can +perform multiple write operations in fewer calls to the database. + +Consider a situation that requires you to insert documents, update +documents, and delete documents for the same task. If you use +the individual write methods to perform each type of operation, each write +accesses the database separately. You can use a bulk write operation to +optimize the number of calls your application makes to the server. + +You can use the ``IMongoCollection.BulkWrite()`` or +``IMongoCollection.BulkWriteAsync()`` method to perform bulk write +operations on a single collection. Each method takes a list of +``WriteModel`` instances that describe the write operations +to perform. + +Sample Data +~~~~~~~~~~~ + +The examples in this guide use the ``sample_restaurants.restaurants`` collection +from the :atlas:`Atlas sample datasets `. To learn how to create a +free MongoDB Atlas cluster and load the sample datasets, see the +:ref:`` tutorial. + +Define the Write Operations +--------------------------- + +For each write operation you want to perform, create an instance of one of +the following ``WriteModel`` classes: + +- ``DeleteManyModel`` +- ``DeleteOneModel`` +- ``InsertOneModel`` +- ``ReplaceOneModel`` +- ``UpdateManyModel`` +- ``UpdateOneModel`` + +The following sections show how to create and use instances of the preceding classes +to perform the corresponding write operation in a bulk write operation. + +.. tip:: Bulk Write Operations with POCOs + + The examples in this guide use the ``BsonDocument`` type for the ``TDocument`` type + in all generic classes. You can also use a Plain Old CLR Object (POCO) for these + classes. To do so, you must define a class that represents the documents in your + collection. The class must have properties that match the fields in your documents. + For more information, see :ref:`csharp-poco`. + +Insert Operations +~~~~~~~~~~~~~~~~~ + +To perform an insert operation, create an ``InsertOneModel`` +instance and specify the document you want to insert. + +The following example creates an instance of the +``InsertOneModel`` class. This instance directs the driver to +insert a document in which the ``"name"`` field is ``"Mongo's Deli"`` +into the ``restaurants`` collection. + +.. literalinclude:: /includes/fundamentals/code-examples/CollectionBulkWrite.cs + :start-after: start-insert-one + :end-before: end-insert-one + :language: csharp + :copyable: + :dedent: + +To insert multiple documents, create an instance of ``InsertOneModel`` +for each document. + +.. important:: Duplicate Key Error + + When performing a bulk operation, the ``InsertOneModel`` cannot + insert a document with an ``_id`` that already exists in the + collection. In this situation, the driver throws a + ``MongoBulkWriteException``. + +Update Operations +~~~~~~~~~~~~~~~~~ + +To update a single document, create an instance of +``UpdateOneModel`` and pass the following arguments: + +- **Query filter** that specifies the criteria used to match documents + in your collection. To learn more about specifying a query, see + :manual:`Query and Projection Operators + ` in the {+mdb-server+} manual. + +- **Update document** that describes the update to perform. To learn + more about specifying an update, see :manual:`Update Operators + ` in the {+mdb-server+} manual. + +An ``UpdateOneModel`` instance specifies an update for *the first* +document that matches your query filter. + +In the following code example, the ``UpdateOneModel`` object +represents an update operation on the ``restaurants`` collection. +The operation matches the first document in the collection where the value of the ``name`` +field is ``"Mongo's Deli"``. It then updates the value of the ``cuisine`` field in the +matched document to ``"Sandwiches and Salads"``. + +.. literalinclude:: /includes/fundamentals/code-examples/CollectionBulkWrite.cs + :start-after: start-update-one + :end-before: end-update-one + :language: csharp + :copyable: + :dedent: + +To update multiple documents, create an instance of ``UpdateManyModel`` and pass +the same arguments as for ``UpdateOneModel``. The ``UpdateManyModel`` +class specifies updates for *all* documents that match your query +filter. + +In the following code example, the ``UpdateManyModel`` object +represents an update operation on the ``restaurants`` collection. +The operation matches all documents in the collection where +the value of the ``name`` field is ``"Mongo's Deli"``. It then updates +the value of the ``cuisine`` field to ``"Sandwiches and Salads"``. + +.. literalinclude:: /includes/fundamentals/code-examples/CollectionBulkWrite.cs + :start-after: start-update-many + :end-before: end-update-many + :language: csharp + :copyable: + :dedent: + +Replace Operations +~~~~~~~~~~~~~~~~~~ + +A replace operation removes all fields and values of a specified document and +replaces them with new fields and values that you specify. To perform a +replace operation, create an instance of ``ReplaceOneModel`` and pass a +query filter and the fields and values you want to replace the matching +document with. + +In the following example, the ``ReplaceOneModel`` object +represents a replace operation on the ``restaurants`` collection. +The operation matches the document in the collection +where the value of the ``restaurant_id`` field is ``"1234"``. It then +removes all fields other than ``_id`` from this document, and sets new values in the +``name``, ``cuisine``, ``borough``, and ``restaurant_id`` fields. + +.. literalinclude:: /includes/fundamentals/code-examples/CollectionBulkWrite.cs + :start-after: start-replace-one + :end-before: end-replace-one + :language: csharp + :copyable: + :dedent: + +To replace multiple documents, you must create an instance of +``ReplaceOneModel`` for each document. + +Delete Operations +~~~~~~~~~~~~~~~~~ + +To delete a document, create an instance of ``DeleteOneModel`` and pass a +query filter specifying the document you want to delete. A +``DeleteOneModel`` instance provides instructions to delete +only *the first* document that matches your query filter. + +In the following code example, the ``DeleteOneModel`` object +represents a delete operation on the ``restaurants`` collection. +The operation matches and deletes the first document +where the value of the ``restaurant_id`` field is ``"5678"``. + +.. literalinclude:: /includes/fundamentals/code-examples/CollectionBulkWrite.cs + :start-after: start-delete-one + :end-before: end-delete-one + :language: csharp + :copyable: + :dedent: + +To delete multiple documents, create an instance of ``DeleteManyModel`` and pass a +query filter specifying the documents you want to delete. An instance of +``DeleteManyModel`` provides instructions to remove *all* documents that +match your query filter. + +In the following code example, the ``DeleteManyModel`` object +represents a delete operation on the ``restaurants`` collection. +The operation matches and deletes all documents +where the value of the ``name`` field is ``"Mongo's Deli"``. + +.. literalinclude:: /includes/fundamentals/code-examples/CollectionBulkWrite.cs + :start-after: start-delete-many + :end-before: end-delete-many + :language: csharp + :copyable: + :dedent: + +.. _csharp-bulkwrite-method: + +Perform the Bulk Operation +-------------------------- + +After you define a ``WriteModel`` instance for each operation that you want to perform, +create an instance of a class that implements the ``IEnumerable`` interface. Add your +``WriteModel`` objects to this ``IEnumerable``, then pass the ``IEnumerable`` +to the ``BulkWrite()`` or ``BulkWriteAsync()`` method. By default, these methods run +the operations in the order they're defined in the list. + +.. tip:: IEnumerable + + ``Array`` and ``List`` are two common classes that implement the + ``IEnumerable`` interface. + +Select from the following tabs to view how to use the synchronous ``BulkWrite()`` method +and the asynchronous ``BulkWriteAsync()`` method to perform a bulk write +operation on the ``restaurants`` collection: + +.. tabs:: + + .. tab:: Synchronous + :tabid: bulk-write-sync + + .. literalinclude:: /includes/fundamentals/code-examples/CollectionBulkWrite.cs + :start-after: start-bulk-write-sync + :end-before: end-bulk-write-sync + :language: csharp + :copyable: + :dedent: + + .. tab:: Asynchronous + :tabid: bulk-write-async + + .. literalinclude:: /includes/fundamentals/code-examples/CollectionBulkWrite.cs + :start-after: start-bulk-write-async + :end-before: end-bulk-write-async + :language: csharp + :copyable: + :dedent: + +The preceding code examples produce the following output: + +.. code-block:: shell + :copyable: false + + MongoDB.Driver.BulkWriteResult1+Acknowledged[MongoDB.Bson.BsonDocument] + +.. note:: + + When the driver runs a bulk operation, it uses the write concern of the + target collection. The driver reports all write concern errors after + attempting all operations, regardless of execution order. + +Customize Bulk Write Operations +------------------------------- + +When you call the ``BulkWrite()`` or ``BulkWriteAsync()`` method, you can pass an +instance of the ``BulkWriteOptions`` class. The ``BulkWriteOptions`` class +contains the following properties, which represent options you can use to configure the +bulk write operation: + +.. list-table:: + :widths: 30 70 + :header-rows: 1 + + * - Property + - Description + + * - ``BypassDocumentValidation`` + - | Specifies whether the operation bypasses document-level validation. For more + information, see :manual:`Schema + Validation ` in the {+mdb-server+} + manual. + | Defaults to ``False``. + + * - ``Comment`` + - | A comment to attach to the operation, in the form of a ``BsonValue``. For + more information, see the :manual:`delete command + fields ` guide in the + {+mdb-server+} manual. + + * - ``IsOrdered`` + - | If ``True``, the driver performs the write operations in the order + provided. If an error occurs, the remaining operations are not + attempted. + | + | If ``False``, the driver performs the operations in an + arbitrary order and attempts to perform all operations. If any of the write + operations in an unordered bulk write fail, the driver + reports the errors only after attempting all operations. + | Defaults to ``True``. + + * - ``Let`` + - | A map of parameter names and values, in the form of a ``BsonDocument``. Values + must be constant or closed + expressions that don't reference document fields. For more information, + see the :manual:`let statement + ` in the + {+mdb-server+} manual. + +The following code examples use a ``BulkWriteOptions`` object to perform +an unordered bulk write operation: + +.. tabs:: + + .. tab:: Synchronous + :tabid: bulk-write-options-sync + + .. literalinclude:: /includes/fundamentals/code-examples/CollectionBulkWrite.cs + :start-after: start-bulk-write-options-sync + :end-before: end-bulk-write-options-sync + :language: csharp + :copyable: + :dedent: + + .. tab:: Asynchronous + :tabid: bulk-write-options-async + + .. literalinclude:: /includes/fundamentals/code-examples/CollectionBulkWrite.cs + :start-after: start-bulk-write-options-async + :end-before: end-bulk-write-options-async + :language: csharp + :copyable: + :dedent: + +Return Value +------------ + +The ``BulkWrite()`` and ``BulkWriteAsync()`` methods return a +``BulkWriteResult`` object that contains the following properties: + +.. list-table:: + :widths: 30 70 + :header-rows: 1 + + * - Property + - Description + + * - ``IsAcknowledged`` + - | Indicates whether the server acknowledged the bulk write operation. If the + value of this property is ``False`` and you try to access any other property + of the ``BulkWriteResult`` object, the driver throws an exception. + + * - ``DeletedCount`` + - | The number of documents deleted, if any. + + * - ``InsertedCount`` + - | The number of documents inserted, if any. + + * - ``MatchedCount`` + - | The number of documents matched for an update, if applicable. + + * - ``ModifiedCount`` + - | The number of documents modified, if any. + + * - ``IsModifiedCountAvailable`` + - | Indicates whether the modified count is available. + + * - ``Upserts`` + - | A list that contains information about each request that + resulted in an upsert operation. + + * - ``RequestCount`` + - | The number of requests in the bulk operation. + +Handling Exceptions +------------------- + +If any of the operations in a bulk write operation fail, the {+driver-short+} throws a +``BulkWriteError`` and does not perform any further operations. + +A ``BulkWriteError`` object contains the ``Index`` property that +describes the index of the request that resulted in an error. + +Additional Information +---------------------- + +To learn how to perform individual write operations, see the following guides: + +- :ref:`csharp-update-one` +- :ref:`csharp-update-many` +- :ref:`csharp-insert-guide` +- :ref:`csharp-delete-guide` +- :ref:`csharp-replace-operation` + +To learn more about any of the methods or types discussed in this +guide, see the following API documentation: + +- `BulkWrite() <{+new-api-root+}/MongoDB.Driver/MongoDB.Driver.IMongoCollection-1.BulkWrite.html>`__ +- `BulkWriteAsync() <{+new-api-root+}/MongoDB.Driver/MongoDB.Driver.IMongoCollection-1.BulkWriteAsync.html>`__ +- `BulkWriteOptions <{+new-api-root+}/MongoDB.Driver/MongoDB.Driver.BulkWriteOptions.-ctor.html>`__ +- `BulkWriteResult <{+new-api-root+}/MongoDB.Driver/MongoDB.Driver.BulkWriteResult.html>`__ +- `InsertOneModel <{+new-api-root+}/MongoDB.Driver/MongoDB.Driver.InsertOneModel-1.html>`__ +- `UpdateOneModel <{+new-api-root+}/MongoDB.Driver/MongoDB.Driver.UpdateOneModel-1.html>`__ +- `UpdateManyModel <{+new-api-root+}/MongoDB.Driver/MongoDB.Driver.UpdateManyModel-1.html>`__ +- `ReplaceOneModel <{+new-api-root+}/MongoDB.Driver/MongoDB.Driver.ReplaceOneModel-1.html>`__ +- `DeleteOneModel <{+new-api-root+}/MongoDB.Driver/MongoDB.Driver.DeleteOneModel-1.html>`__ +- `DeleteManyModel <{+new-api-root+}/MongoDB.Driver/MongoDB.Driver.DeleteManyModel-1.html>`__ +- `BulkWriteError <{+new-api-root+}/MongoDB.Driver/MongoDB.Driver.BulkWriteError.html>`__ diff --git a/source/includes/fundamentals/code-examples/CollectionBulkWrite.cs b/source/includes/fundamentals/code-examples/CollectionBulkWrite.cs new file mode 100644 index 00000000..59df03da --- /dev/null +++ b/source/includes/fundamentals/code-examples/CollectionBulkWrite.cs @@ -0,0 +1,157 @@ +using MongoDB.Driver; +using MongoDB.Bson; + +var connectionString = Environment.GetEnvironmentVariable("MONGODB_URI"); +if (connectionString == null) +{ + Console.WriteLine("You must set your 'MONGODB_URI' environment variable. To learn how to set it, see https://www.mongodb.com/docs/drivers/csharp/current/quick-start/#set-your-connection-string"); + Environment.Exit(0); +} + +var client = new MongoClient(connectionString); +var collection = client.GetDatabase("db").GetCollection("rest"); + +// start-insert-one +var insertOneModel = new InsertOneModel( + new BsonDocument{ + { "name", "Mongo's Deli" }, + { "cuisine", "Sandwiches" }, + { "borough", "Manhattan" }, + { "restaurant_id", "1234" } + } +); +// end-insert-one + +// start-update-one +var updateOneModel = new UpdateOneModel( + Builders.Filter.Eq("name", "Mongo's Deli"), + Builders.Update.Set("cuisine", "Sandwiches and Salads") +); +// end-update-one + +// start-update-many +var updateManyModel = new UpdateManyModel( + Builders.Filter.Eq("name", "Mongo's Deli"), + Builders.Update.Set("cuisine", "Sandwiches and Salads") +); +// end-update-many + +// start-replace-one +var replaceOneModel = new ReplaceOneModel( + Builders.Filter.Eq("restaurant_id", "1234"), + new BsonDocument{ + { "name", "Mongo's Pizza" }, + { "cuisine", "Pizza" }, + { "borough", "Brooklyn" }, + { "restaurant_id", "5678" } + } +); +// end-replace-one + +// start-delete-one +var deleteOneModel = new DeleteOneModel( + Builders.Filter.Eq("restaurant_id", "5678") +); +// end-delete-one + +// start-delete-many +var deleteManyModel = new DeleteManyModel( + Builders.Filter.Eq("name", "Mongo's Deli") +); +// end-delete-many + +// start-bulk-write-sync +var models = new List> +{ + new InsertOneModel( + new BsonDocument{ + { "name", "Mongo's Deli" }, + { "cuisine", "Sandwiches" }, + { "borough", "Manhattan" }, + { "restaurant_id", "1234" } + } + ), + new InsertOneModel( + new BsonDocument{ + { "name", "Mongo's Deli" }, + { "cuisine", "Sandwiches" }, + { "borough", "Brooklyn" }, + { "restaurant_id", "5678" } + } + ), + new UpdateManyModel( + Builders.Filter.Eq("name", "Mongo's Deli"), + Builders.Update.Set("cuisine", "Sandwiches and Salads") + ), + new DeleteOneModel( + Builders.Filter.Eq("restaurant_id", "1234") + ) +}; + +var results = collection.BulkWrite(models); +Console.WriteLine(results); +// end-bulk-write-sync + +// start-bulk-write-async +var models = new List> +{ + new InsertOneModel( + new BsonDocument{ + { "name", "Mongo's Deli" }, + { "cuisine", "Sandwiches" }, + { "borough", "Manhattan" }, + { "restaurant_id", "1234" } + } + ), + new InsertOneModel( + new BsonDocument{ + { "name", "Mongo's Deli" }, + { "cuisine", "Sandwiches" }, + { "borough", "Brooklyn" }, + { "restaurant_id", "5678" } + } + ), + new UpdateManyModel( + Builders.Filter.Eq("name", "Mongo's Deli"), + Builders.Update.Set("cuisine", "Sandwiches and Salads") + ), + new DeleteOneModel( + Builders.Filter.Eq("restaurant_id", "1234") + ) +}; + +var results = await collection.BulkWriteAsync(models); +Console.WriteLine(results); +// end-bulk-write-async + +// start-bulk-write-options-sync +var models = new List> +{ +new DeleteOneModel( + Builders.Filter.Eq("restaurant_id", "5678") +) +}; + +var options = new BulkWriteOptions +{ + IsOrdered = false, +}; + +collection.BulkWrite(models, options); +// end-bulk-write-options-sync + +// start-bulk-write-options-async +var models = new List> +{ +new DeleteOneModel( + Builders.Filter.Eq("restaurant_id", "5678") +) +}; + +var options = new BulkWriteOptions +{ + IsOrdered = false, +}; + +await collection.BulkWriteAsync(models, options); +// end-bulk-write-options-async diff --git a/source/whats-new.txt b/source/whats-new.txt index 8eedc444..074847f1 100644 --- a/source/whats-new.txt +++ b/source/whats-new.txt @@ -28,7 +28,6 @@ Learn what's new in: * :ref:`Version 2.24 ` * :ref:`Version 2.23 ` * :ref:`Version 2.22 ` -* :ref:`Version 2.21 ` .. _upcoming-breaking-changes: @@ -212,4 +211,5 @@ The 2.22 driver release includes the following new features: - Reduced memory allocation when using encryption. - Added logging messages for server discovery and monitoring (SDAM) events. For more information on these events, see the - `MongoDB SDAM Logging and Monitoring specification. `__ \ No newline at end of file + `MongoDB SDAM Logging and Monitoring specification. + `__