189 lines
6.7 KiB
ReStructuredText
189 lines
6.7 KiB
ReStructuredText
Client Bulk Write Operations
|
|
=============================
|
|
|
|
.. testsetup::
|
|
|
|
from pymongo import MongoClient
|
|
|
|
client = MongoClient()
|
|
client.drop_database("client_bulk_example")
|
|
db = client.client_bulk_example
|
|
client.db.drop_collection("test_one")
|
|
client.db.drop_collection("test_two")
|
|
client.db.drop_collection("test_three")
|
|
client.db.drop_collection("test_four")
|
|
client.db.drop_collection("test_five")
|
|
client.db.drop_collection("test_six")
|
|
|
|
The :meth:`~pymongo.mongo_client.MongoClient.bulk_write`
|
|
method has been added to :class:`~pymongo.mongo_client.MongoClient` in PyMongo 4.9.
|
|
This method enables users to perform batches of write operations **across
|
|
multiple namespaces** in a minimized number of round trips, and
|
|
to receive detailed results for each operation performed.
|
|
|
|
.. note:: This method requires MongoDB server version 8.0+.
|
|
|
|
Basic Usage
|
|
------------
|
|
|
|
A list of insert, update, and delete operations can be passed into the
|
|
:meth:`~pymongo.mongo_client.MongoClient.bulk_write` method. Each request
|
|
must include the namespace on which to perform the operation.
|
|
|
|
PyMongo will automatically split the given requests into smaller sub-batches based on
|
|
the maximum message size accepted by MongoDB, supporting very large bulk write operations.
|
|
|
|
The return value is an instance of
|
|
:class:`~pymongo.results.ClientBulkWriteResult`.
|
|
|
|
.. _summary_client_bulk:
|
|
|
|
Summary Results
|
|
.................
|
|
|
|
By default, the returned :class:`~pymongo.results.ClientBulkWriteResult` instance will contain a
|
|
summary of the types of operations performed in the bulk write, along with their respective counts.
|
|
|
|
.. doctest::
|
|
:options: +NORMALIZE_WHITESPACE
|
|
|
|
>>> from pymongo import InsertOne, DeleteOne, UpdateOne
|
|
>>> models = [
|
|
... InsertOne(namespace="db.test_one", document={"_id": 1}),
|
|
... InsertOne(namespace="db.test_two", document={"_id": 2}),
|
|
... DeleteOne(namespace="db.test_one", filter={"_id": 1}),
|
|
... UpdateOne(
|
|
... namespace="db.test_two",
|
|
... filter={"_id": 4},
|
|
... update={"$inc": {"j": 1}},
|
|
... upsert=True,
|
|
... ),
|
|
... ]
|
|
>>> result = client.bulk_write(models)
|
|
>>> result.inserted_count
|
|
2
|
|
>>> result.deleted_count
|
|
1
|
|
>>> result.modified_count
|
|
0
|
|
>>> result.upserted_count
|
|
1
|
|
|
|
.. _verbose_client_bulk:
|
|
|
|
Verbose Results
|
|
.................
|
|
|
|
If the ``verbose_results`` parameter is set to True, the returned :class:`~pymongo.results.ClientBulkWriteResult`
|
|
instance will also include detailed results about each successful operation performed as part of the bulk write.
|
|
|
|
.. doctest::
|
|
:options: +NORMALIZE_WHITESPACE
|
|
|
|
>>> from pymongo import InsertOne, DeleteMany, ReplaceOne, UpdateMany
|
|
>>> models = [
|
|
... DeleteMany(
|
|
... namespace="db.test_two", filter={}
|
|
... ), # Delete all documents from the previous example
|
|
... InsertOne(namespace="db.test_one", document={"_id": 1}),
|
|
... InsertOne(namespace="db.test_one", document={"_id": 2}),
|
|
... InsertOne(namespace="db.test_two", document={"_id": 3}),
|
|
... UpdateMany(namespace="db.test_one", filter={}, update={"$set": {"foo": "bar"}}),
|
|
... ReplaceOne(
|
|
... namespace="db.test_two", filter={"j": 1}, replacement={"_id": 4}, upsert=True
|
|
... ),
|
|
... ]
|
|
>>> result = client.bulk_write(models, verbose_results=True)
|
|
>>> result.delete_results
|
|
{0: DeleteResult({'ok': 1.0, 'idx': 0, 'n': 2}, ...)}
|
|
>>> result.insert_results
|
|
{1: InsertOneResult(1, ...),
|
|
2: InsertOneResult(2, ...),
|
|
3: InsertOneResult(3, ...)}
|
|
>>> result.update_results
|
|
{4: UpdateResult({'ok': 1.0, 'idx': 4, 'n': 2, 'nModified': 2}, ...),
|
|
5: UpdateResult({'ok': 1.0, 'idx': 5, 'n': 1, 'nModified': 0, 'upserted': {'_id': 4}}, ...)}
|
|
|
|
|
|
Handling Errors
|
|
----------------
|
|
|
|
If any errors occur during the bulk write, a :class:`~pymongo.errors.ClientBulkWriteException` will be raised.
|
|
If a server, connection, or network error occurred, the ``error`` field of the exception will contain
|
|
that error.
|
|
|
|
Individual write errors or write concern errors get recorded in the ``write_errors`` and ``write_concern_errors`` fields of the exception.
|
|
The ``partial_result`` field gets populated with the results of any operations that were successfully completed before the exception was raised.
|
|
|
|
.. _ordered_client_bulk:
|
|
|
|
Ordered Operations
|
|
....................
|
|
|
|
In an ordered bulk write (the default), if an individual write fails, no further operations will get executed.
|
|
For example, a duplicate key error on the third operation below aborts the remaining two operations.
|
|
|
|
.. doctest::
|
|
:options: +NORMALIZE_WHITESPACE
|
|
|
|
>>> from pymongo import InsertOne, DeleteOne
|
|
>>> from pymongo.errors import ClientBulkWriteException
|
|
>>> models = [
|
|
... InsertOne(namespace="db.test_three", document={"_id": 3}),
|
|
... InsertOne(namespace="db.test_four", document={"_id": 4}),
|
|
... InsertOne(namespace="db.test_three", document={"_id": 3}), # Duplicate _id
|
|
... InsertOne(namespace="db.test_four", document={"_id": 5}),
|
|
... DeleteOne(namespace="db.test_three", filter={"_id": 3}),
|
|
... ]
|
|
>>> try:
|
|
... client.bulk_write(models)
|
|
... except ClientBulkWriteException as cbwe:
|
|
... exception = cbwe
|
|
...
|
|
>>> exception.write_errors
|
|
[{'ok': 0.0,
|
|
'idx': 2,
|
|
'code': 11000,
|
|
'errmsg': 'E11000 duplicate key error ... dup key: { _id: 3 }', ...
|
|
'op': {'insert': 0, 'document': {'_id': 3}}}]
|
|
>>> exception.partial_result.inserted_count
|
|
2
|
|
>>> exception.partial_result.deleted_count
|
|
0
|
|
|
|
.. _unordered_client_bulk:
|
|
|
|
Unordered Operations
|
|
.....................
|
|
|
|
If the ``ordered`` parameter is set to False, all operations in the bulk write will be attempted, regardless of any individual write errors that occur.
|
|
For example, the fourth and fifth write operations below get executed successfully, despite the duplicate key error on the third operation.
|
|
|
|
.. doctest::
|
|
:options: +NORMALIZE_WHITESPACE
|
|
|
|
>>> from pymongo import InsertOne, DeleteOne
|
|
>>> from pymongo.errors import ClientBulkWriteException
|
|
>>> models = [
|
|
... InsertOne(namespace="db.test_five", document={"_id": 5}),
|
|
... InsertOne(namespace="db.test_six", document={"_id": 6}),
|
|
... InsertOne(namespace="db.test_five", document={"_id": 5}), # Duplicate _id
|
|
... InsertOne(namespace="db.test_six", document={"_id": 7}),
|
|
... DeleteOne(namespace="db.test_five", filter={"_id": 5}),
|
|
... ]
|
|
>>> try:
|
|
... client.bulk_write(models, ordered=False)
|
|
... except ClientBulkWriteException as cbwe:
|
|
... exception = cbwe
|
|
...
|
|
>>> exception.write_errors
|
|
[{'ok': 0.0,
|
|
'idx': 2,
|
|
'code': 11000,
|
|
'errmsg': 'E11000 duplicate key error ... dup key: { _id: 5 }', ...
|
|
'op': {'insert': 0, 'document': {'_id': 5}}}]
|
|
>>> exception.partial_result.inserted_count
|
|
3
|
|
>>> exception.partial_result.deleted_count
|
|
1
|