Docs Menu
Docs Home
/ / /
Kotlin Coroutine
/ / /

Bulk Operations

On this page

  • Overview
  • Collection Bulk Write
  • Insert Operation
  • Replace Operation
  • Update Operation
  • Delete Operation
  • Order of Execution
  • Client Bulk Write
  • Insert Operation
  • Replace Operation
  • Bulk Write Options
  • Summary
  • MongoCollection.bulkWrite()
  • MongoClient.bulkWrite()

In this guide, you can learn how to use bulk operations in the Kotlin driver.

To perform a single create, replace, update, or delete operation, you can use the corresponding method. For example, to insert one document and replace one document, you can use the insertOne() and replaceOne() methods. When you use these methods, your client makes one call to the database for each operation.

By using a bulk write operation, you can perform multiple write operations in fewer database calls. You can perform bulk write operations at the following levels:

  • Collection: You can use the MongoCollection.bulkWrite() method to perform bulk write operations on a single collection. In this method, each kind of write operation requires at least one database call. For example, MongoCollection.bulkWrite() puts multiple update operations in one call, but makes two separate calls to the database for an insert operation and a replace operation.

  • Client: If your application connects to MongoDB server version 8.0 or later, you can use the MongoClient.bulkWrite() method to perform bulk write operations on multiple collections and databases in the same cluster. This method performs all write operations in one database call.

Bulk write operations contain one or more write operations. To perform a bulk write operation at the collection level, pass a List of WriteModel documents to the MongoCollection.bulkWrite() method. A WriteModel is a model that represents a write operation.

The MongoCollection.bulkWrite() method performs each kind of write operation in a separate database call. For example, when you pass DeleteOneModel, DeleteManyModel, and ReplaceOneModel objects to the method, it performs two calls: one for the delete operations and one for the replace operation.

Note

When the client splits operations into separate database calls, it might reorder operations for efficiency if the bulk write operation is not ordered. To learn more about operation execution order, see the Order of Execution section.

The following sections show how to create and use each WriteModel document. The examples in each section use the following documents in the people collection:

{ "_id": 1, "name": "Karen Sandoval", "age": 31 }
{ "_id": 2, "name": "William Chin", "age": 54 }
{ "_id": 8, "name": "Shayla Ray", "age": 20 }

This data is modeled by the following Kotlin data class:

data class Person(
@BsonId val id: Int,
val name: String,
val age: Int? = null,
val location: String? = null
)

For more information about the methods and classes mentioned in this section, see the following API documentation:

To perform an insert operation, create an InsertOneModel specifying the document you want to insert. To insert multiple documents, you must create an InsertOneModel for each document you want to insert.

The following example creates an InsertOneModel for two documents describing people:

val juneDoc = InsertOneModel(Person(3, "June Carrie", 17))
val kevinDoc = InsertOneModel(Person(4, "Kevin Moss", 22))

Important

When performing a bulkWrite() operation, the InsertOneModel cannot insert a document with an _id that already exists in the collection. In this case, the driver throws a MongoBulkWriteException.

The following example tries to insert two documents where the _id values are 1 and 3. Since there is already a document with an _id of 1 in the collection, the operation results in an error:

try {
val bulkOperations = listOf(
(InsertOneModel(Person(1, "James Smith", 13))),
(InsertOneModel(Person(3, "Colin Samuels")))
)
val bulkWrite = collection.bulkWrite(bulkOperations)
} catch (e: MongoBulkWriteException) {
println("A MongoBulkWriteException occurred with the following message: " + e.message)
}
A MongoBulkWriteException occurred with the following message:
Bulk write operation error on server sample-shard-00-02.pw0q4.mongodb.net:27017.
Write errors: [BulkWriteError{index=0, code=11000, message='E11000 duplicate key
error collection: crudOps.bulkWrite index: _id_ dup key: { _id: 1 }', details={}}].

To learn about why the driver didn't insert the document with the _id of 3, see the Order of Execution section.

For more information about the methods and classes mentioned in this section, see the InsertOneModel API documentation.

To perform a replace operation, create a ReplaceOneModel specifying a query filter for the document you want to replace and the replacement document.

Important

When performing a bulkWrite(), the ReplaceOneModel cannot make changes that violate unique index constraints on the collection. Additionally, the model does not perform the replace operation if there are no matches to the query filter.

The following example creates a ReplaceOneModel to replace a document where the _id is 1 with a document that contains the additional location field:

val filter = Filters.eq("_id", 1)
val insert = Person(1, "Celine Stork", location = "San Diego, CA")
val doc = ReplaceOneModel(filter, insert)

If multiple documents match the query filter specified in the ReplaceOneModel instance, the operation replaces the first result. You can specify a sort in a ReplaceOptions instance to apply an order to matched documents before the driver performs the replace operation, as shown in the following code:

val opts = ReplaceOptions().sort(Sorts.ascending("_id"))

For more information about the methods and classes mentioned in this section, see the following resources:

To perform an update operation, create an UpdateOneModel or an UpdateManyModel that specifies a query filter and an update document.

The UpdateOneModel updates the first document that matches your query filter and the UpdateManyModel updates all the documents that match your query filter.

Important

When performing a bulkWrite(), the UpdateOneModel and UpdateManyModel types cannot make changes that violate unique index constraints on the collection. Additionally, the models do not perform update operations if there are no matches to the query filter.

The following example creates an UpdateOneModel to increment the age field by 1 in a document where the _id is 2:

val filter = Filters.eq("_id", 2)
val update = Updates.inc(Person::age.name, 1)
val doc = UpdateOneModel<Person>(filter, update)

If multiple documents match the query filter specified in the UpdateOneModel instance, the operation updates the first result. You can specify a sort in an UpdateOptions instance to apply an order to matched documents before the driver performs the update operation, as shown in the following code:

val opts = UpdateOptions().sort(Sorts.ascending("_id"))

For more information about the methods and classes mentioned in this section, see the following resources:

To perform a delete operation, create a DeleteOneModel or a DeleteManyModel that specifies a query filter for documents you want to delete.

The DeleteOneModel deletes the first document that matches your query filter and the DeleteManyModel deletes all the documents that match your query filter.

Important

When performing a bulkWrite(), the DeleteOneModel and DeleteManyModel types do not delete any documents if there are no matches to the query filter.

The following example creates a DeleteOneModel to delete a document where the _id is 1 and a DeleteManyModel to delete documents where the age value is less than 30:

val deleteId1 = DeleteOneModel<Person>(Filters.eq("_id", 1))
val deleteAgeLt30 = DeleteManyModel<Person>(Filters.lt(Person::age.name, 30))

For more information about the methods and classes mentioned in this section, see the following API documentation:

The bulkWrite() method accepts an optional BulkWriteOptions as a second parameter to specify if you want to execute the bulk operations as ordered or unordered.

By default, the bulkWrite() method executes bulk operations in order. This means that the operations execute in the order you added them to the list until any error occurs.

The following example performs these bulk operations:

  • An insert operation for a document where the name is "Zaynab Omar" and the age is 37

  • A replace operation for a document where the _id is 1 with a new document that contains the location field

  • An update operation for a document where the _id is 6 to change the name field

  • A delete operation for all documents that have an age value greater than 50

val insertMdl = InsertOneModel(Person(6, "Zaynab Omar", 37))
val replaceMdl = ReplaceOneModel(
Filters.eq("_id", 1),
Person(1, "Sandy Kane", location = "Helena, MT")
)
val updateMdl = UpdateOneModel<Person>(
Filters.eq("_id", 6),
Updates.set(Person::name.name, "Zaynab Hassan")
)
val deleteMdl = DeleteManyModel<Person>(Filters.gt(Person::age.name, 50))
val bulkOperations = listOf(
insertMdl,
replaceMdl,
updateMdl,
deleteMdl
)
val result = collection.bulkWrite(bulkOperations)

After running this example, your collection contains the following document:

{ "_id": 1, "name": "Sandy Kane", "location": "Helena, MT" }
{ "_id": 8, "name": "Shayla Ray", "age": 20 }
{ "_id": 6, "name": "Zaynab Hassan", "age": 37 }

You can also execute bulk operations in any order by passing false to the ordered() method on a BulkWriteOptions object. This means that all the write operations execute regardless of errors. If any errors occur, the driver reports them at the end.

The following code shows how to execute a bulk operation with no order of execution:

val options = BulkWriteOptions().ordered(false)
val unorderedResult = collection.bulkWrite(bulkOperations, options)

Note

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

In the preceding example, if the bulkWrite() method performed the insert operation after the update operation, the update operation would not produce changes because the document did not exist at that point in time. The collection would then contain the following documents:

{ "_id": 1, "name": "Sandy Kane", "location": "Helena, MT" }
{ "_id": 8, "name": "Shayla Ray", "age": 20 }
{ "_id": 6, "name": "Zaynab Omar", "age": 37 }

For more information about the methods and classes mentioned in this section, see the following API documentation:

When connecting to a deployment running MongoDB server 8.0 or later, you can use the MongoClient.bulkWrite() method to write to multiple databases and collections in the same cluster. The MongoClient.bulkWrite() method performs all write operations in a single call.

The MongoClient.bulkWrite() method takes a list of ClientNamespacedWriteModel instances to represent different write operations. You can construct instances of the ClientNamespacedWriteModel interface by using instance methods. For example, an instance of ClientNamespacedInsertOneModel represents an operation to insert one document, and you can create this model by using the ClientNamespacedWriteModel.insertOne() method.

Note

Bulk Write Errors

If any of the write operations fail, the driver raises a ClientBulkWriteException and does not perform any further individual operations. ClientBulkWriteException includes a BulkWriteError that can be accessed by using the ClientBulkWriteException.getWriteErrors() method, which provides details of the individual failure.

The models and their corresponding instance methods are described in the table below.

Model
Instance Method
Description
Parameters

ClientNamespacedInsertOneModel

insertOne()

Creates a model to insert a document into the namespace.

namespace: Database and collection to write to

document: Document to insert

ClientNamespacedUpdateOneModel

updateOne()

Creates a model to update the first document in the namespace that matches filter.

namespace: Database and collection to write to

filter: Filter that selects which document to update

update: Update to apply to matching document

updatePipeline: Update pipeline to apply to matching document

options: (optional) Options to apply when updating document

You must pass a value for either the update or updatePipeline parameter.

ClientNamespacedUpdateManyModel

updateMany()

Creates a model to update all documents in the namespace that match filter.

namespace: Database and collection to write to

filter: Filter that selects which documents to update

update: Update to apply to matching documents

updatePipeline: Update pipeline to apply to matching documents

options: (optional) Options to apply when updating documents

You must pass a value for either the update or updatePipeline parameter.

ClientNamespacedReplaceOneModel

replaceOne()

Creates a model to replace the first document in the namespace that matches filter.

namespace: Database and collection to write to

filter: Filter that selects which document to replace

replacement: Replacement document

options: (optional) Options to apply when replacing documents

ClientNamespacedDeleteOneModel

deleteOne()

Creates a model to delete the first document in the namespace that matches filter.

namespace: Database and collection to write to

filter: Filter that selects which document to delete

option: (optional) Options to apply when deleting document

ClientNamespacedDeleteManyModel

deleteMany()

Creates a model to delete all documents in the namespace that match filter.

namespace: Database and collection to write to

filter: Filter that selects which documents to delete

option: (optional) Options to apply when deleting documents

The following sections provide examples of how to use the client bulkWrite() method. The sample data is modeled by the following Kotlin data classes:

data class Person(
@BsonId val id: Int,
val name: String,
)
data class Object(
@BsonId val id: Int,
val type: String,
)

To learn more about the methods and classes mentioned in this section, see the following API documentation:

This example shows how to use the bulkWrite() method to insert two documents. One document is inserted into the sample_db.people collection, while the other document is inserted into the sample_db.objects collection. The MongoNamespace instance defines the databases and collections that each write operation applies to.

val docsToInsert = mutableListOf<ClientNamespacedWriteModel>()
docsToInsert.add(ClientNamespacedWriteModel
.insertOne(
MongoNamespace("sample_db", "people"),
Person(2, "Julia Smith")
)
)
docsToInsert.add(ClientNamespacedWriteModel
.insertOne(
MongoNamespace("sample_db", "objects"),
Object(2, "washing machine")
)
)
val clientBulkResult = client.bulkWrite(docsToInsert)

The following example shows how to use the bulkWrite() method to replace existing documents in the sample_db.people and sample_db.things collections.

val docsReplacements = mutableListOf<ClientNamespacedWriteModel>()
docsReplacements.add(ClientNamespacedWriteModel
.replaceOne(
MongoNamespace("sample_db", "people"),
Filters.eq(Person::id.name, 1),
Person(1, "Frederic Hilbert")
)
)
docsReplacements.add(ClientNamespacedWriteModel
.replaceOne(
MongoNamespace("sample_db", "objects"),
Filters.eq(Object::id.name, 1),
Object(1, "ironing board")
)
)
val clientBulkResult = client.bulkWrite(docsReplacements)

After this example runs successfully, the document that has an _id value of 1 in the people collection is replaced with a new document. The document in the things collection that has an _id value of 1 is replaced with a new document.

You can pass an instance of ClientBulkWriteOptions to the bulkWrite() method to specify options when running the bulk write operations.

By default, the individual operations in a bulk operation are executed in the order that you specify them until an error occurs, or until they execute successfully. However, you can pass false to the ordered() method on the ClientBulkWriteOptions interface to perform write operations in an unordered way. When using the unordered option, an error-producing operation does not prevent execution of other write operations in the call to the bulkWrite() method.

The following code sets the ordered() method on an instance of ClientBulkWriteOptions and performs a bulk write operation to insert multiple documents.

val namespace = MongoNamespace("sample_db", "people")
val options = ClientBulkWriteOptions
.clientBulkWriteOptions()
.ordered(false)
val bulkOperations = listOf(
ClientNamespacedWriteModel.insertOne(
namespace,
Person(2, "Rudra Suraj")
),
// Causes duplicate key error
ClientNamespacedWriteModel.insertOne(
namespace,
Person(2, "Wendy Zhang")
),
ClientNamespacedWriteModel.insertOne(
namespace,
Person(4, "Mario Bianchi")
)
)
val result = client.bulkWrite(bulkOperations, options)

Even though the write operation inserting a document with a duplicate key results in an error, the other operations are executed because the write operation is unordered.

To learn more about the methods and classes mentioned in this section, see the following API documentation:

To perform a bulk operation, you create and pass a list of WriteModel instances to the bulkWrite() method.

There are 6 different WriteModel subtypes: InsertOneModel, ReplaceOneModel, UpdateOneModel, UpdateManyModel, DeleteOneModel and DeleteManyModel.

There are two ways to execute the bulkWrite() method:

  • Ordered, which performs the bulk operations in order until an error occurs, if any

  • Unordered, which performs all the bulk operations in any order and reports errors at the end, if any

To learn more about the collection bulkWrite command, see the db.collection.bulkWrite() method reference in the MongoDB server Manual.

When connecting to a deployment running MongoDB server version 8.0 or later, you can use the MongoClient.bulkWrite() method to perform bulk operations on multiple databases and collections at once.

To perform a client bulk operation, you create an pass a list of ClientNamespacedWriteModel instances to this method.

There are six subtypes of ClientNamespacedWriteModel that are used to represent write operations. To construct these write models, you can use the corresponding ClientNamespacedWriteModel methods insertOne(), updateOne(), updateMany(), replaceOne(), deleteOne(), and deleteMany(). These methods take a MongoNamespace object that defines which database and collection to write to.

The MongoClient.bulkWrite() method can also take a ClientBulkWriteOptions object to specify different options for how the command is executed.

To learn more about the client bulkWrite command, see the bulkWrite() method reference in the MongoDB server Manual.

Back

Insert or Update in a Single Operation