Skip to content

DOCSP-39699: Bulk writes #83

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Sep 10, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
129 changes: 129 additions & 0 deletions source/includes/write/bulk-write.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
import com.mongodb.ConnectionString;
import com.mongodb.MongoClientSettings;
import com.mongodb.ServerApi;
import com.mongodb.ServerApiVersion;

import com.mongodb.bulk.BulkWriteResult;
import com.mongodb.client.model.InsertOneModel;
import com.mongodb.client.model.UpdateOneModel;
import com.mongodb.client.model.UpdateManyModel;
import com.mongodb.client.model.ReplaceOneModel;
import com.mongodb.client.model.DeleteOneModel;
import com.mongodb.client.model.DeleteManyModel;
import com.mongodb.client.model.BulkWriteOptions;
import com.mongodb.reactivestreams.client.MongoCollection;

import org.bson.Document;

import com.mongodb.reactivestreams.client.MongoClient;
import com.mongodb.reactivestreams.client.MongoClients;
import com.mongodb.reactivestreams.client.MongoDatabase;
import org.reactivestreams.Publisher;
import reactor.core.publisher.Mono;

import java.util.Arrays;

import static com.mongodb.client.model.Filters.eq;
import static com.mongodb.client.model.Updates.set;

class BulkWrite {
public static void main(String[] args) throws InterruptedException {
// Replace the placeholder with your Atlas connection string
String uri = "<connection string>";

// Construct a ServerApi instance using the ServerApi.builder() method
ServerApi serverApi = ServerApi.builder()
.version(ServerApiVersion.V1)
.build();

MongoClientSettings settings = MongoClientSettings.builder()
.applyConnectionString(new ConnectionString(uri))
.serverApi(serverApi)
.build();

// Create a new client and connect to the server
try (MongoClient mongoClient = MongoClients.create(settings)) {
MongoDatabase sample_restaurants = mongoClient.getDatabase("sample_restaurants");
MongoCollection<Document> restaurants = sample_restaurants.getCollection("restaurants");


// start-bulk-insert-one
InsertOneModel<Document> operation = new InsertOneModel<>(
new Document("name", "Mongo's Deli")
.append("cuisine", "Sandwiches"));
// end-bulk-insert-one

// start-bulk-update-one
UpdateOneModel<Document> operation = new UpdateOneModel<>(
eq("name", "Mongo's Deli"),
set("cuisine", "Sandwiches and Salads"));
// end-bulk-update-one

// start-bulk-update-many
UpdateManyModel<Document> operation = new UpdateManyModel<>(
eq("name", "Mongo's Deli"),
set("cuisine", "Sandwiches and Salads"));
// end-bulk-update-many

// start-bulk-replace-one
ReplaceOneModel<Document> operation = new ReplaceOneModel<>(
eq("name", "Original Pizza"),
new Document("name", "Mongo's Pizza")
.append("borough", "Manhattan"));
// end-bulk-replace-one

// start-bulk-delete-one
DeleteOneModel<Document> operation = new DeleteOneModel<>(
eq("restaurant_id", "5678"));
// end-bulk-delete-one

// start-bulk-delete-many
DeleteManyModel<Document> operation = new DeleteManyModel<>(
eq("name", "Mongo's Deli"));
// end-bulk-delete-many

// start-bulk-write-mixed
Publisher<BulkWriteResult> bulkWritePublisher = restaurants.bulkWrite(
Arrays.asList(new InsertOneModel<>(
new Document("name", "Mongo's Deli")
.append("cuisine", "Sandwiches")
.append("borough", "Manhattan")
.append("restaurant_id", "1234")),
new InsertOneModel<>(new Document("name", "Mongo's Deli")
.append("cuisine", "Sandwiches")
.append("borough", "Brooklyn")
.append("restaurant_id", "5678")),
new UpdateManyModel<>(eq("name", "Mongo's Deli"),
set("cuisine", "Sandwiches and Salads")),
new DeleteOneModel<>(eq("restaurant_id", "1234"))));

BulkWriteResult bulkResult = Mono.from(bulkWritePublisher).block();

System.out.println(bulkResult.toString());
// end-bulk-write-mixed

// start-bulk-write-unordered
Publisher<BulkWriteResult> bulkWritePublisher = restaurants.bulkWrite(
Arrays.asList(new InsertOneModel<>(
new Document("name", "Mongo's Deli")
.append("cuisine", "Sandwiches")
.append("borough", "Manhattan")
.append("restaurant_id", "1234")),
new InsertOneModel<>(new Document("name", "Mongo's Deli")
.append("cuisine", "Sandwiches")
.append("borough", "Brooklyn")
.append("restaurant_id", "5678")),
new UpdateManyModel<>(eq("name", "Mongo's Deli"),
set("cuisine", "Sandwiches and Salads")),
new DeleteOneModel<>(eq("restaurant_id", "1234"))),
new BulkWriteOptions().ordered(false));

BulkWriteResult bulkResult = Mono.from(bulkWritePublisher).block();

System.out.println(bulkResult.toString());
// end-bulk-write-unordered

}
}

}
329 changes: 281 additions & 48 deletions source/write/bulk-writes.txt
Original file line number Diff line number Diff line change
@@ -1,58 +1,291 @@
.. _javars-bulk-writes:
.. _java-rs-bulk-write:

=====================
Bulk Write Operations
=====================

.. contents:: On this page
:local:
:backlinks: none
:depth: 2
:class: singlecol

.. facet::
:name: genre
:values: reference

.. meta::
:keywords: code example, multiple changes

Starting in v2.6, MongoDB supports bulk write commands
for insert, update, and delete operations in a way that allows the
driver to implement the correct semantics for ``BulkWriteResult`` and
``BulkWriteException``.

There are two types of bulk operations, ordered and unordered bulk
operations:

1. Ordered bulk operations execute all the operations in order and
error out on the first write error.
#. Unordered bulk operations execute all the operations and report any
the errors. Unordered bulk operations do not guarantee an order of
execution.

.. include:: /includes/subscriber-note.rst

The following code provides examples using ordered and unordered
operations:

.. code-block:: java

// Ordered bulk operation - order is guaranteed
collection.bulkWrite(
Arrays.asList(new InsertOneModel<>(new Document("_id", 4)),
new InsertOneModel<>(new Document("_id", 5)),
new InsertOneModel<>(new Document("_id", 6)),
new UpdateOneModel<>(new Document("_id", 1),
new Document("$set", new Document("x", 2))),
new DeleteOneModel<>(new Document("_id", 2)),
new ReplaceOneModel<>(new Document("_id", 3),
new Document("_id", 3).append("x", 4))))
.subscribe(new ObservableSubscriber<BulkWriteResult>());

// Unordered bulk operation - no guarantee of order of operation
collection.bulkWrite(
Arrays.asList(new InsertOneModel<>(new Document("_id", 4)),
new InsertOneModel<>(new Document("_id", 5)),
new InsertOneModel<>(new Document("_id", 6)),
new UpdateOneModel<>(new Document("_id", 1),
new Document("$set", new Document("x", 2))),
new DeleteOneModel<>(new Document("_id", 2)),
new ReplaceOneModel<>(new Document("_id", 3),
new Document("_id", 3).append("x", 4))),
new BulkWriteOptions().ordered(false))
.subscribe(new ObservableSubscriber<BulkWriteResult>());
:keywords: insert, update, replace, code example

Overview
--------
In this guide, you can learn how to perform multiple write operations in a single database call by using **bulk write operations**.

Consider a scenario in which you want to insert a document into a collection,
update multiple other documents, then delete a document. If you use
individual methods, each operation requires its own database call. This guide
shows you how to use bulk write operations to reduce the number of calls to the database.

Sample Data
~~~~~~~~~~~

The examples in this guide use the ``sample_restaurants.restaurants`` collection
from the :atlas:`Atlas sample datasets </sample-data>`. To learn how to create a
free MongoDB Atlas cluster and load the sample datasets, see the
:ref:`<java-rs-getting-started>` tutorial.

.. include:: /includes/reactor-note.rst

Define the Write Operations
---------------------------

For each write operation you want to perform, create an instance of one of
the following classes:

- ``InsertOneModel``
- ``UpdateOneModel``
- ``UpdateManyModel``
- ``ReplaceOneModel``
- ``DeleteOneModel``
- ``DeleteManyModel``

Then, pass a list of these instances to the ``bulkWrite()`` method.

The following sections show how to create and use instances of the preceding classes.

Insert Operations
~~~~~~~~~~~~~~~~~

To perform an insert operation, create an instance of ``InsertOneModel`` and
pass in the document you want to insert.

The following example creates an instance of ``InsertOneModel``:

.. literalinclude:: /includes/write/bulk-write.java
:start-after: start-bulk-insert-one
:end-before: end-bulk-insert-one
:language: java
:copyable:
:dedent:

To insert multiple documents, create an instance of ``InsertOneModel`` for each document.

Update Operations
~~~~~~~~~~~~~~~~~

To update a document, create an instance of ``UpdateOneModel`` and pass in
the following arguments:

- **Query filter** that specifies the criteria used to match documents in your collection.
- **Update operation** you want to perform. For more information about update
operations, see the :manual:`Field Update Operators
</reference/operator/update-field/>` guide in the {+mdb-server+} manual.

``UpdateOneModel`` updates *the first* document that matches your query filter.

The following example creates an instance of ``UpdateOneModel``:

.. literalinclude:: /includes/write/bulk-write.java
:start-after: start-bulk-update-one
:end-before: end-bulk-update-one
:language: java
:copyable:
:dedent:

To update multiple documents, create an instance of ``UpdateManyModel`` and pass in
the same arguments. ``UpdateManyModel`` updates *all* documents that match your query
filter.

The following example creates an instance of ``UpdateManyModel``:

.. literalinclude:: /includes/write/bulk-write.java
:start-after: start-bulk-update-many
:end-before: end-bulk-update-many
:language: java
:copyable:
:dedent:

Replace Operations
~~~~~~~~~~~~~~~~~~

A replace operation removes all fields and values of a specified document, aside from
the ``_id`` field, and replaces them with new ones. To perform a replace operation, create
an instance of ``ReplaceOneModel`` and pass in a query filter and the fields and values
you want to store in the matching document.

The following example creates an instance of ``ReplaceOneModel``:

.. literalinclude:: /includes/write/bulk-write.java
:start-after: start-bulk-replace-one
:end-before: end-bulk-replace-one
:language: java
:copyable:
:dedent:

To replace multiple documents, create an instance of ``ReplaceOneModel`` for each document.

Delete Operations
~~~~~~~~~~~~~~~~~

To delete a document, create an instance of ``DeleteOneModel`` and pass in a
query filter specifying the document you want to delete. ``DeleteOneModel`` removes
only *the first* document that matches your query filter.

The following example creates an instance of ``DeleteOneModel``:

.. literalinclude:: /includes/write/bulk-write.java
:start-after: start-bulk-delete-one
:end-before: end-bulk-delete-one
:language: java
:copyable:
:dedent:

To delete multiple documents, create an instance of ``DeleteManyModel`` and pass in a
query filter specifying the documents you want to delete. ``DeleteManyModel`` removes
*all* documents that match your query filter.

The following example creates an instance of ``DeleteManyModel``:

.. literalinclude:: /includes/write/bulk-write.java
:start-after: start-bulk-delete-many
:end-before: end-bulk-delete-many
:language: java
:copyable:
:dedent:

Call the ``bulkWrite()`` Method
--------------------------------

After you define a class instance for each operation you want to perform,
pass a list of these instances to the ``bulkWrite()`` method.
By default, the method runs the operations in the order
they're defined in the list.

The following example performs multiple write operations by using the
``bulkWrite()`` method:

.. io-code-block::
:copyable:

.. input:: /includes/write/bulk-write.java
:start-after: start-bulk-write-mixed
:end-before: end-bulk-write-mixed
:language: java
:dedent:

.. output::

AcknowledgedBulkWriteResult{insertedCount=2, matchedCount=2, removedCount=1, modifiedCount=2, upserts=[], inserts=[BulkWriteInsert{index=0, id=BsonObjectId{value=66a7e0a6c08025218b657208}}, BulkWriteInsert{index=1, id=BsonObjectId{value=66a7e0a6c08025218b657209}}]}

If any of the write operations fail, the {+driver-short+} signals a
``MongoBulkWriteException`` and does not perform any further individual operations.
``MongoBulkWriteException`` includes a ``BulkWriteError`` that can be accessed by using the
``MongoBulkWriteException.getWriteErrors()`` method, which provides details of the
individual failure.

.. note::

When the {+driver-short+} runs a bulk operation, it uses the ``writeConcern`` of the
collection on which the operation is running. The driver reports all write
concern errors after attempting all operations, regardless of execution order.

Customize Bulk Write Operations
-------------------------------

The ``BulkWriteOptions`` class contains methods that modify
the behavior of the ``bulkWrite()`` method. To use the ``BulkWriteOptions``
class, construct a new instance of the class, then call one or more of its methods
to modify the write operation. You can chain these method calls together.
To modify the behavior of the write operation, pass the class instance as the last
argument to the ``bulkWrite()`` method.

You can use the following methods in the ``BulkWriteOptions`` class
to modify a write method. All methods are optional.

.. list-table::
:widths: 30 70
:header-rows: 1

* - Method
- Description

* - ``bypassDocumentValidation(Boolean bypassDocumentValidation)``
- | Specifies whether the bulk write operation bypasses document validation. This lets you
perform write operations on documents that don't meet the schema validation requirements, if any
exist. For more information about schema validation, see :manual:`Schema
Validation </core/schema-validation/#schema-validation>` in the MongoDB
Server manual.

* - ``comment(Bson comment)``
- | Attaches a ``Bson`` comment to the operation. For more information, see the :manual:`insert command
fields </reference/command/insert/#command-fields>` guide in the
MongoDB Server manual.

* - ``comment(String comment)``
- | Attaches a ``String`` comment to the operation. For more information, see the :manual:`insert command
fields </reference/command/insert/#command-fields>` guide in the
MongoDB Server manual.

* - ``let(Bson variables)``
- | Specifies a map of parameter names and values. Values must be constant or closed
expressions that don't reference document fields. For more information,
see the :manual:`let statement
</reference/command/update/#std-label-update-let-syntax>` in the
MongoDB Server manual.

* - ``ordered(Boolean ordered)``
- | If set to ``True``, the driver performs the individual operations in the order
provided. If an individual operation fails, the driver will not execute any
subsequent individual operations.
| Defaults to ``True``.

The following example calls the ``bulkWrite()`` method from the preceding
example but sets the ``ordered`` option to ``False``:

.. io-code-block::
:copyable:

.. input:: /includes/write/bulk-write.java
:start-after: start-bulk-write-unordered
:end-before: end-bulk-write-unordered
:language: java
:dedent:

.. output::

AcknowledgedBulkWriteResult{insertedCount=2, matchedCount=2, removedCount=1, modifiedCount=2, upserts=[], inserts=[BulkWriteInsert{index=0, id=BsonObjectId{value=66a7e03cce430c5854b6caf9}}, BulkWriteInsert{index=1, id=BsonObjectId{value=66a7e03cce430c5854b6cafa}}]}

If any of the write operations in an unordered bulk write fail, the {+driver-short+}
reports the errors only after attempting all operations.

.. note::

Unordered bulk operations do not guarantee order of execution. The order can
differ from the way you list them to optimize the runtime.

Additional Information
----------------------

To learn how to perform individual write operations, see the following guides:

- :ref:`java-rs-write-insert`
- :ref:`java-rs-write-update-docs`
- :ref:`java-rs-write-replace`
- :ref:`java-rs-write-delete-docs`

API Documentation
~~~~~~~~~~~~~~~~~

To learn more about any of the methods or types discussed in this
guide, see the following API documentation:

- `bulkWrite() <{+api+}/mongodb-driver-reactivestreams/com/mongodb/reactivestreams/client/MongoCollection.html#bulkWrite(com.mongodb.reactivestreams.client.ClientSession,java.util.List)>`__
- `InsertOneModel <{+api+}/mongodb-driver-core/com/mongodb/client/model/InsertOneModel.html>`__
- `UpdateOneModel <{+api+}/mongodb-driver-core/com/mongodb/client/model/UpdateOneModel.html>`__
- `UpdateManyModel <{+api+}/mongodb-driver-core/com/mongodb/client/model/UpdateManyModel.html>`__
- `ReplaceOneModel <{+api+}/mongodb-driver-core/com/mongodb/client/model/ReplaceOneModel.html>`__
- `DeleteOneModel <{+api+}/mongodb-driver-core/com/mongodb/client/model/DeleteOneModel.html>`__
- `DeleteManyModel <{+api+}/mongodb-driver-core/com/mongodb/client/model/DeleteManyModel.html>`__
- `BulkWriteResult <{+api+}/mongodb-driver-core/com/mongodb/bulk/BulkWriteResult.html>`__
- `BulkWriteError <{+api+}/mongodb-driver-core/com/mongodb/bulk/BulkWriteError.html>`__
- `MongoBulkWriteException <{+api+}/mongodb-driver-core/com/mongodb/MongoBulkWriteException.html>`__