Docs Menu
Docs Home
/ / /
Rust Driver
/ / /

Bulk Operations

On this page

  • Overview
  • Sample Data
  • Bulk Operation Types
  • Insert
  • Replace
  • Update
  • Delete
  • Return Type
  • Modify Behavior
  • Example
  • Write to Mixed Namespaces
  • Additional Information

In this guide, you can learn how to use the Rust driver to perform bulk operations.

Bulk operations perform multiple write operations against one or more namespaces. A namespace is a combination of the database name and the collection name, in the format <database>.<collection>. Since you perform bulk operations on a Client instance, you can perform bulk operations against any namespace in the cluster accessed by your client.

You can perform bulk operations to reduce the number of calls to the server. Instead of sending a request for each operation, bulk operations perform multiple operations within one action.

This guide includes the following sections:

  • Sample Data presents the sample data that is used by the bulk operation examples

  • Bulk Operation Types describes how to use WriteModel types to perform bulk insert, replace, update, and delete operations

  • Return Type describes the return value of the bulk_write() method and how to access information about the bulk operation

  • Modify Behavior describes how to modify the default behavior of the bulk_write() method

  • Write to Mixed Namespaces describes how to perform a bulk operation on multiple namespaces in one method call

  • Additional Information provides links to resources and API documentation for types and methods mentioned in this guide

Important

To perform bulk write operations, ensure that your application meets the following requirements:

  • You are connected to MongoDB Server version 8.0 or later.

  • You are using Rust driver version 3.0 or later.

The examples in this guide use the following sample documents, which are stored in the mushrooms collection in the db database:

let docs = vec![
doc! {"name" : "portobello", "color" : "brown", "edible" : true },
doc! {"name" : "chanterelle", "color" : "yellow", "edible" : true },
doc! {"name" : "oyster", "color" : "white", "edible" : true },
doc! {"name" : "fly agaric", "color" : "red", "edible" : false },
];

You can also use custom struct types to represent your sample data. For an example that performs a bulk operation by using Mushroom structs to model the same data, see the Insert Structs Example on this page.

To perform a bulk write operation, pass an array of WriteModel enum instances to the bulk_write() method.

In this section, you can learn how to perform the following bulk write operations by defining their corresponding WriteModel types:

Tip

You can also perform multiple types of write operations in a single bulk_write() method call. To view an example that passes an UpdateOneModel and an InsertOneModel to the same bulk_write() call, see the Modify Behavior example in this guide.

To perform a bulk insert operation, create an InsertOneModel instance for each document you want to insert. Then, pass a list of models to the bulk_write() method.

The following table describes InsertOneModel fields that you can set by calling their corresponding builder methods:

Field
Description
namespace
The namespace on which the insert is performed.
Type: Namespace
document
The document to insert.
Type: Document

This example performs the following actions:

  • Specifies two InsertOneModel instances in an array. Each InsertOneModel represents a document to be inserted into the db.mushrooms namespace.

  • Passes the array of models to the bulk_write() method.

  • Prints the number of inserted documents.

let mushrooms: Collection<Document> = client.database("db").collection("mushrooms");
let models = vec![
InsertOneModel::builder()
.namespace(mushrooms.namespace())
.document(doc! {
"name": "lion's mane",
"color": "white",
"edible": true
})
.build(),
InsertOneModel::builder()
.namespace(mushrooms.namespace())
.document(doc! {
"name": "angel wing",
"color": "white",
"edible": false
})
.build(),
];
let result = client.bulk_write(models).await?;
println!("Inserted documents: {}", result.inserted_count);
Inserted documents: 2

You can also model your documents by using structs and bulk insert struct instances into the db.mushrooms namespace.

This example performs the same operation as the preceding Insert Documents Example but inserts instances of the following Mushroom struct type:

#[derive(Serialize)]
struct Mushroom {
name: String,
color: String,
edible: bool,
}

The following code uses the insert_one_model() method to construct an InsertOneModel from each Mushroom instance, then inserts both models in a bulk operation:

let mushrooms: Collection<Mushroom> = client.database("db").collection("mushrooms");
let lions_mane = Mushroom {
name: "lion's mane".to_string(),
color: "white".to_string(),
edible: true,
};
let angel_wing = Mushroom {
name: "angel wing".to_string(),
color: "white".to_string(),
edible: false,
};
let lions_mane_model = mushrooms.insert_one_model(lions_mane)?;
let angel_wing_model = mushrooms.insert_one_model(angel_wing)?;
let result = client.bulk_write([lions_mane_model, angel_wing_model]).await?;
println!("Inserted documents: {}", result.inserted_count);
Inserted documents: 2

Tip

To learn more about custom struct types and serialization in the Rust driver, see the guide on Data Modeling and Serialization.

To perform a bulk replace operation, create a ReplaceOneModel instance for each document you want to replace. Then, pass a list of models to the bulk_write() method.

The following table describes ReplaceOneModel fields that you can set by calling their corresponding builder methods:

Field
Description
namespace
The namespace on which the operation is performed.
Type: Namespace
filter
The filter that matches the document you want to replace.
Type: Document
replacement
The replacement document.
Type: Document
collation
(Optional) The collation to use when sorting results. To learn more about collations, see the Collations guide.
Type: Document
hint
(Optional) The index to use for the operation. To learn more about indexes, see the Indexes guide.
Type: Bson
upsert
(Optional) Whether a new document is created if no document matches the filter.
By default, this field is set to false.
Type: bool

This example performs the following actions:

  • Specifies two ReplaceOneModel instances in an array. The ReplaceOneModel instances contain instructions to replace documents representing mushrooms in the db.mushrooms namespace.

  • Passes the array of models to the bulk_write() method.

  • Prints the number of modified documents.

let mushrooms: Collection<Document> = client.database("db").collection("mushrooms");
let models = vec![
ReplaceOneModel::builder()
.namespace(mushrooms.namespace())
.filter(doc! { "name": "portobello" })
.replacement(doc! {
"name": "cremini",
"color": "brown",
"edible": true
})
.build(),
ReplaceOneModel::builder()
.namespace(mushrooms.namespace())
.filter(doc! { "name": "oyster" })
.replacement(doc! {
"name": "golden oyster",
"color": "yellow",
"edible": true
})
.upsert(true)
.build(),
];
let result = client.bulk_write(models).await?;
println!("Modified documents: {}", result.modified_count);
Modified documents: 2

To perform a bulk update operation, create an UpdateOneModel or UpdateManyModel instance for each update you want to make. Then, pass a list of models to the bulk_write() method. An UpdateOneModel updates only one document that matches a filter, while an UpdateManyModel updates all documents that match a filter.

The following table describes UpdateOneModel and UpdateManyModel fields that you can set by calling their corresponding builder methods:

Field
Description
namespace
The namespace on which the operation is performed.
Type: Namespace
filter
The filter that matches one or more documents you want to update. When specified in an UpdateOneModel, only the first matching document will be updated. When specified in an UpdateManyModel, all matching documents will be updated.
Type: Document
update
The update to perform.
Type: UpdateModifications
array_filters
(Optional) A set of filters specifying which array elements an update applies to if you are updating an array-valued field.
Type: Array
collation
(Optional) The collation to use when sorting results. To learn more about collations, see the Collations guide.
Type: Document
hint
(Optional) The index to use for the operation. To learn more about indexes, see the Indexes guide.
Type: Bson
upsert
(Optional) Whether a new document is created if no document matches the filter. By default, this field is set to false.
Type: bool

This example performs the following actions:

  • Specifies an UpdateOneModel and an UpdateManyModel instance in an array. These models contain instructions to update documents representing mushrooms in the db.mushrooms namespace.

  • Passes the array of models to the bulk_write() method.

  • Prints the number of modified documents.

let mushrooms: Collection<Document> = client.database("db").collection("mushrooms");
let models = vec![
WriteModel::UpdateOne(
UpdateOneModel::builder()
.namespace(mushrooms.namespace())
.filter(doc! { "name": "fly agaric" })
.update(doc! { "$set": { "name": "fly amanita" } })
.upsert(true)
.build(),
),
WriteModel::UpdateMany(
UpdateManyModel::builder()
.namespace(mushrooms.namespace())
.filter(doc! { "color": "yellow" })
.update(doc! { "$set": { "color": "yellow/orange" } })
.build(),
),
];
let result = client.bulk_write(models).await?;
println!("Modified documents: {}", result.modified_count);
Modified documents: 2

To perform a bulk delete operation, create a DeleteOneModel or DeleteManyModel instance for each delete operation. Then, pass a list of models to the bulk_write() method. A DeleteOneModel deletes only one document that matches a filter, while a DeleteManyModel deletes all documents that match a filter.

The following table describes DeleteOneModel and DeleteManyModel fields that you can set by calling their corresponding builder methods:

Field
Description
namespace
The namespace on which the operation is performed.
Type: Namespace
filter
The filter that matches one or more documents you want to delete. When specified in a DeleteOneModel, only the first matching document will be deleted. When specified in a DeleteManyModel, all matching documents will be deleted.
Type: Document
collation
(Optional) The collation to use when sorting results. To learn more about collations, see the Collations guide.
Type: Document
hint
(Optional) The index to use for the operation. To learn more about indexes, see the Indexes guide.
Type: Bson

This example performs the following actions:

  • Specifies a DeleteOneModel and a DeleteManyModel instance in an array. These models contain instructions to delete documents representing mushrooms in the db.mushrooms namespace.

  • Passes the array of models to the bulk_write() method.

  • Prints the number of deleted documents.

let mushrooms: Collection<Document> = client.database("db").collection("mushrooms");
let models = vec![
WriteModel::DeleteOne(
DeleteOneModel::builder()
.namespace(mushrooms.namespace())
.filter(doc! { "color": "red" })
.build(),
),
WriteModel::DeleteMany(
DeleteManyModel::builder()
.namespace(mushrooms.namespace())
.filter(doc! { "edible": true })
.build(),
),
];
let result = client.bulk_write(models).await?;
println!("Deleted documents: {}", result.deleted_count);
Deleted documents: 4

The bulk_write() method returns a SummaryBulkWriteResult struct instance from which you can access information about your bulk operation.

The SummaryBulkWriteResult type has the following fields:

  • inserted_count: the number of inserted documents

  • matched_count: the number of matched documents

  • modified_count: the number of updated documents

  • upserted_count: the number of upserted documents

  • deleted_count: the number of deleted documents

You can also use the verbose_results() method to see detailed information about each operation. The verbose_results() method returns a VerboseBulkWriteResult struct instance, which has the following fields:

  • delete_results: the results of each successful delete operation

  • insert_results: the results of each successful insert operation

  • update_results: the results of each successful update operation

  • summary: a summary of the results of each operation type

The following example chains the verbose_results() method to the bulk_write() method and prints the results of the update and delete operations:

let models = vec![
WriteModel::DeleteOne(
DeleteOneModel::builder()
.namespace(mushrooms.namespace())
.filter(doc! { "name": "oyster" })
.build(),
),
WriteModel::UpdateOne(
UpdateOneModel::builder()
.namespace(mushrooms.namespace())
.filter(doc! { "name": "chanterelle" })
.update(doc! { "$set": { "season": ["July", "August", "September"] } })
.build(),
),
];
let result = client.bulk_write(models).verbose_results().await?;
println!(
"Update results: {:?}\nDelete results: {:?}\n",
result.update_results, result.delete_results
);
Update results: {1: UpdateResult { matched_count: 1, modified_count: 1, upserted_id: None }}
Delete results: {0: DeleteResult { deleted_count: 1 }}

You can modify the behavior of the bulk_write() method by setting BulkWriteOptions field values. To set these struct fields, chain the fields' corresponding methods to the bulk_write() method.

The BulkWriteOptions struct contains the following fields:

Field
Description
Default Value
ordered
Whether the operations run in the order in which they were specified.
When set to true, one failed operation prevents subsequent operations from running.
When set to false, the server continues to attempt write operations if one fails.
Type: bool
true
bypass_document_validation
Whether document-level validation is bypassed.
Type: bool
false
comment
An arbitrary comment to help trace the operation through the database profiler, currentOp, and logs.
Type: Bson
None
let_vars
A map of parameter names and values to apply to all operations within the bulk write. Values must be constant or closed expressions that do not reference document fields.
Type: Document
None
write_concern
The write concern to use for this bulk operation.
Type: WriteConcern
Inherits the namespace's write concern

This example attempts to perform update and insert operations on the mushrooms collection. The following code sets the ordered field to false by chaining the ordered() method to the bulk_write() method:

let mushrooms: Collection<Document> = client.database("db").collection("mushrooms");
let models = vec![
WriteModel::UpdateOne(UpdateOneModel::builder()
.namespace(mushrooms.namespace())
.filter(doc! { "name": "portobello" })
.update(doc! { "$set": { "_id": 123 } })
.upsert(true)
.build()),
WriteModel::InsertOne(InsertOneModel::builder()
.namespace(mushrooms.namespace())
.document(doc! {
"name": "reishi",
"color": "red/brown",
"edible": true
})
.build()),
];
let result = client.bulk_write(models).ordered(false).await?;
println!(
"Inserted documents: {}\nDeleted documents: {}",
result.inserted_count, result.deleted_count
);
Error: Error { kind: BulkWrite(BulkWriteError { write_concern_errors: [], write_errors:
{0: WriteError { code: 66, code_name: None, message: "Plan executor error during update ::
caused by :: Performing an update on the path '_id' would modify the immutable field '_id'",
details: None }}, partial_result: Some(Summary(SummaryBulkWriteResult { inserted_count: 1,
matched_count: 0, modified_count: 0, upserted_count: 0, deleted_count: 0 })) }),
labels: ... }

The _id field is immutable and cannot be changed in an update operation. Since the UpdateOneModel includes instructions to update this field, the bulk operation returns a BulkWriteError and performs only the insert operation. If you set the ordered field to true, the driver does not attempt any subsequent operations after the unsuccessful update operation, and the driver does not insert any documents.

The preceding examples on this page perform bulk operations on the db.mushrooms namespace. However, you can perform bulk writes on multiple namespaces in a single method call.

The following example inserts one document into the ingredients.sweet namespace and one document into the meals.dessert namespace:

let sweet: Collection<Document> = client
.database("ingredients")
.collection("sweet");
let dessert: Collection<Document> = client
.database("meals")
.collection("dessert");
let models = vec![
InsertOneModel::builder()
.namespace(sweet.namespace())
.document(doc! { "name": "brown sugar", "price": 3.99 })
.build(),
InsertOneModel::builder()
.namespace(dessert.namespace())
.document(doc! { "name": "banana bread", "cook_time": 75 })
.build(),
];
let result = client.bulk_write(models).await?;
println!("Inserted documents: {}", result.inserted_count);
Inserted documents: 2

To learn more about bulk operations, see Bulk Write Operations in the Server manual.

Back

Delete