Bulk Operations
On this page
Overview
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 operationsReturn Type describes the return value of the
bulk_write()
method and how to access information about the bulk operationModify Behavior describes how to modify the default behavior of the
bulk_write()
methodWrite 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.
Sample Data
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.
Bulk Operation Types
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.
Insert
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 |
Insert Documents Example
This example performs the following actions:
Specifies two
InsertOneModel
instances in an array. EachInsertOneModel
represents a document to be inserted into thedb.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
Insert Structs Example
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:
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.
Replace
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 |
Example
This example performs the following actions:
Specifies two
ReplaceOneModel
instances in an array. TheReplaceOneModel
instances contain instructions to replace documents representing mushrooms in thedb.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
Update
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 |
Example
This example performs the following actions:
Specifies an
UpdateOneModel
and anUpdateManyModel
instance in an array. These models contain instructions to update documents representing mushrooms in thedb.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
Delete
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 |
Example
This example performs the following actions:
Specifies a
DeleteOneModel
and aDeleteManyModel
instance in an array. These models contain instructions to delete documents representing mushrooms in thedb.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
Return Type
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 documentsmatched_count
: the number of matched documentsmodified_count
: the number of updated documentsupserted_count
: the number of upserted documentsdeleted_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 operationinsert_results
: the results of each successful insert operationupdate_results
: the results of each successful update operationsummary
: 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 }}
Modify Behavior
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 |
Example
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.
Write to Mixed Namespaces
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
Additional Information
To learn more about bulk operations, see Bulk Write Operations in the Server manual.