Docs Menu
Docs Home
/ / /
Scala Driver
/

Bulk Write Operations

On this page

  • Overview
  • Collection Bulk Write
  • Sample Data
  • Insert Operations
  • Update Operations
  • Replace Operations
  • Delete Operations
  • Perform the Bulk Operation
  • Customize Bulk Write
  • Return Value
  • Client Bulk Write
  • Insert Operations
  • Update Operations
  • Replace Operations
  • Perform the Bulk Operation
  • Customize Bulk Write
  • Additional Information
  • API Documentation

This guide shows you how to use the Scala driver to perform a bulk write operation that makes multiple changes to your data in a single database call.

Consider a scenario in which you want to insert a document, update multiple other documents, then delete a document. If you use individual methods, each operation requires its own database call.

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 Seq of WriteModel documents to the MongoCollection.bulkWrite() method. A WriteModel is a model that represents a write operation.

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

  • 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. The Perform the Bulk Operation section demonstrates how to pass a list of models to the bulkWrite() method to perform the bulk operation.

The examples in this section use the restaurants collection in the sample_restaurants database from the Atlas sample datasets. To access this collection from your Scala application, create a MongoClient that connects to an Atlas cluster and assign the following values to your database and collection variables:

val database: MongoDatabase = mongoClient.getDatabase("sample_restaurants")
val collection: MongoCollection[Document] = database.getCollection("restaurants")

To learn how to create a free MongoDB Atlas cluster and load the sample datasets, see the Get Started with Atlas guide.

To perform an insert operation, create an InsertOneModel instance and specify the document you want to insert.

The following example creates an instance of InsertOneModel:

val insertOneModel = InsertOneModel(
Document("name" -> "Blue Moon Grill",
"borough" -> "Brooklyn",
"cuisine" -> "American")
)

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

Important

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.

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

  • Query filter that specifies the criteria used to match documents in your collection.

  • Update operation that you want to perform. To learn more about update operations, see the Field Update Operators guide in the MongoDB Server manual.

The following example creates an instance of UpdateOneModel:

val updateOneFilter = equal("name", "White Horse Tavern")
val updateOneDoc = set("borough", "Queens")
val updateOneModel = UpdateOneModel(updateOneFilter, updateOneDoc)

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 options = UpdateOptions.sort(ascending("name"))

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.

The following example creates an instance of UpdateManyModel:

val updateManyFilter = equal("name", "Wendy's")
val updateManyDoc = set("cuisine", "Fast food")
val updateManyModel = UpdateManyModel(updateManyFilter, updateManyDoc)

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 the following arguments:

  • Query filter that specifies the criteria used to match documents in your collection

  • Replacement document that specifies the new fields and values to insert

The following example creates an instance of ReplaceOneModel:

val replaceFilter = equal("name", "Cooper Town Diner")
val replaceDoc = Document("name" -> "Smith Town Diner",
"borough" -> "Brooklyn",
"cuisine" -> "American")
val replaceOneModel = ReplaceOneModel(replaceFilter, replaceDoc)

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 options = ReplaceOptions.sort(ascending("name"))

Tip

Replace Multiple Documents

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

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.

The following example creates an instance of DeleteOneModel:

val deleteOneModel = DeleteOneModel(equal("name", "Morris Park Bake Shop"))

To delete multiple documents, create an instance of DeleteManyModel and pass a query filter specifying the document you want to delete. An instance of DeleteManyModel provides instructions to remove all documents that match your query filter.

The following example creates an instance of DeleteManyModel:

val deleteManyModel = DeleteManyModel(equal("cuisine", "Experimental"))

After you define a model instance for each operation that you want to perform, pass a Seq instance containing the models to the MongoCollection.bulkWrite() method. By default, the method runs the operations in the order specified by the list of models.

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

val insertOneModel = InsertOneModel(
Document("name" -> "Red's Pizza",
"borough" -> "Brooklyn",
"cuisine" -> "Pizzeria")
)
val updateOneModel = UpdateOneModel(equal("name", "Moonlit Tavern"), set("borough", "Queens"))
val deleteManyModel = DeleteManyModel(equal("name", "Crepe"))
val writes = Seq(insertOneModel, updateOneModel, deleteManyModel)
val observable = collection.bulkWrite(writes)
observable.subscribe(
(result: BulkWriteResult) => println(s"Success: $result"),
(error: Throwable) => println(s"Error: ${error.getMessage}"),
() => println("Completed")
)
Success: AcknowledgedBulkWriteResult{insertedCount=1, matchedCount=1, removedCount=1,
modifiedCount=1, upserts=[], inserts=[BulkWriteInsert{index=0, id=BsonObjectId{value=...}}]}
Completed

If any of the write operations fail, the Scala driver raises a BulkWriteError and does not perform any further operations. BulkWriteError provides a details item that includes the operation that failed and details about the exception.

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.

The MongoCollection.bulkWrite() method optionally accepts a BulkWriteOptions parameter, which specifies options that you can use to configure the bulk write operation. If you don't specify any options, the driver performs the bulk operation with default settings. To modify the behavior of the write operation, pass the class instance as the last argument to the bulkWrite() method.

The following table describes the setter methods that you can use to configure a BulkWriteOptions instance:

Method
Description

ordered()

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.
Defaults to true.

bypassDocumentValidation()

Specifies whether the update operation bypasses document validation. This lets you update documents that don't meet the schema validation requirements, if any exist. For more information about schema validation, see Schema Validation in the MongoDB Server manual.
Defaults to false.

comment()

Sets a comment to attach to the operation.

let()

Provides a map of parameter names and values to set top-level variables for the operation. Values must be constant or closed expressions that don't reference document fields.

The following code creates options and sets the ordered option to false to specify an unordered bulk write. Then, the example uses the bulkWrite() method to perform a bulk operation:

val options = BulkWriteOptions().ordered(false)
val observable = collection.bulkWrite(writes, options)

If any of the write operations in an unordered bulk write fail, the Scala driver reports the errors only after attempting all operations.

Note

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

The bulkWrite() method returns a SingleObservable object that contains a BulkWriteResult. You can access information from the BulkWriteResult instance by subscribing to the observable and using the following methods:

Method
Description

wasAcknowledged()

Indicates if the server acknowledged the write operation.

getDeletedCount()

The number of documents deleted, if any.

getInsertedCount()

The number of documents inserted, if any.

getInserts()

The list of inserted documents, if any.

getMatchedCount()

The number of documents matched for an update, if applicable.

getModifiedCount()

The number of documents modified, if any.

getUpserts()

The list of upserted documents, if any.

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 containing one or more 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.

The following table describes the models and their corresponding instance methods:

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 some examples of how to create models and use the client bulkWrite() method.

This example shows how to create models that contain instructions to insert two documents. One document is inserted into the db.people collection, and the other document is inserted into the db.things collection. The MongoNamespace instance defines the target database and collection that each write operation applies to.

val personToInsert = ClientNamespacedWriteModel.insertOne(
MongoNamespace("db", "people"),
Document("name" -> "Julia Smith")
)
val thingToInsert = ClientNamespacedWriteModel.insertOne(
MongoNamespace("db", "things"),
Document("object" -> "washing machine")
);

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

val personUpdate = ClientNamespacedWriteModel.updateOne(
MongoNamespace("db", "people"),
equal("name", "Freya Polk"),
inc("age", 1)
)
val thingUpdate = ClientNamespacedWriteModel.updateMany(
MongoNamespace("db", "things"),
equal("category", "electronic"),
set("manufacturer", "Premium Technologies")
)

This example increments the value of the age field by 1 in the document that has a name value of "Freya Polk" in the people collection. It also sets the value of the manufacturer field to "Premium Technologies" in all documents that have a category value of "electronic" in the things collection.

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

val options = ClientUpdateOneOptions
.clientUpdateOneOptions()
.sort(ascending("_id"))

The following example shows how to create models to replace existing documents in the db.people and db.things collections:

val personReplacement = ClientNamespacedWriteModel.replaceOne(
MongoNamespace("db", "people"),
equal("_id", 1),
Document("name" -> "Frederic Hilbert")
)
val thingReplacement = ClientNamespacedWriteModel.replaceOne(
MongoNamespace("db", "things"),
equal("_id", 1),
Document("object" -> "potato")
)

The preceding code example replaces the following documents with new documents:

  • Document in the people collection that has an _id value of 1

  • Document in the things collection that has an _id value of 1

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

val options = ClientReplaceOneOptions
.clientReplaceOneOptions()
.sort(ascending("_id"))

After you define a ClientNamespacedWriteModel instance for each operation that you want to perform, pass a list of these instances to the client bulkWrite() method. By default, the method runs the operations in the order that you specify them.

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

val peopleNamespace = MongoNamespace("db", "people")
val thingsNamespace = MongoNamespace("db", "things")
val writeModels = List(
ClientNamespacedWriteModel.insertOne(
peopleNamespace,
Document("name" -> "Corey Kopper")
),
ClientNamespacedWriteModel.replaceOne(
thingsNamespace,
equal("_id", 1),
Document("object" -> "potato")
)
)
val observable = mongoClient.bulkWrite(writeModels)
observable.subscribe(
(result: ClientBulkWriteResult) => println(result.toString),
(error: Throwable) => println(s"Error: ${error.getMessage}"),
() => println("Completed")
)
AcknowledgedSummaryClientBulkWriteResult{insertedCount=1, matchedCount=1, ...}

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 information about the failure.

You can pass an instance of ClientBulkWriteOptions to the bulkWrite() method to customize how the driver performs the bulk write operation.

By default, the driver runs the individual operations in a bulk operation in the order that you specify them. The driver runs the operations until an error occurs, or until the total bulk operation successfully completes.

However, you can pass false to the ordered() method when creating a ClientBulkWriteOptions instance to direct the driver to perform write operations in an unordered way. If you pass false, the driver attempts to run all write operations in the bulk write operation, even if one operation produces an error.

The following code sets the ordered option to false in an instance of ClientBulkWriteOptions and performs a bulk write operation to insert multiple documents:

val namespace = MongoNamespace("db", "people")
val options = ClientBulkWriteOptions.clientBulkWriteOptions().ordered(false)
val writeModels = List(
ClientNamespacedWriteModel.insertOne(namespace, Document("_id" -> 1, "name" -> "Rudra Suraj")),
// Causes a duplicate key error
ClientNamespacedWriteModel.insertOne(namespace, Document("_id" -> 1, "name" -> "Mario Bianchi")),
ClientNamespacedWriteModel.insertOne(namespace, Document("name" -> "Wendy Zhang"))
)
val observable = mongoClient.bulkWrite(writeModels, options)

Because the write operation is unordered, the driver performs all the non-erroring operations even though the write operation that inserts a document with a duplicate key results in an error.

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

  • Insert Documents

  • Update Documents

  • Delete Documents

  • Replace Documents

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

Back

Delete