Back to Blog
Python

Python PyMongo Update, Delete, and Bulk Operations

python pymongo update delete and bulk operations: Learn how to perform update, delete, and bulk write operations with PyMongo, including syntax, operators, error handl...

PyMongoMongoDBPythonCRUDBulk Operations
Illustration of PyMongo update, delete, and bulk write operations on MongoDB documents

python pymongo update delete and bulk operations requires a clear understanding of the core syntax, runtime behavior, and practical implementation patterns demonstrated in the examples below.

When working with MongoDB from Python, PyMongo provides a straightforward API for updating, deleting, and bulk-writing documents. This article covers the core methods, their behavior, and the tradeoffs you need to consider when mixing operations.

Core Update and Delete Methods

PyMongo exposes update_one(), update_many(), delete_one(), and delete_many() on Collection objects. Each method takes a filter and, for updates, a set of update operators. The _one variants affect at most one document, while the _many variants affect all matching documents.

from pymongo import MongoClient client = MongoClient("mongodb://localhost:27017") db = client["inventory"] collection = db["items"] # Update the first document where sku is "ABC" collection.update_one( {"sku": "ABC"}, {"$set": {"price": 19.99}} ) # Update all documents where category is "clearance" collection.update_many( {"category": "clearance"}, {"$mul": {"price": 0.8}} ) # Delete one document with a specific id collection.delete_one({"_id": 12345}) # Delete all documents older than a date from datetime import datetime, timedelta cutoff = datetime.utcnow() - timedelta(days=30) collection.delete_many({"created_at": {"$lt": cutoff}})

The filter uses the same query syntax as find(). The update document must contain update operators like $set, $unset, $inc, or $push; replacing the entire document without operators is allowed but rarely useful because it removes all other fields.

Update Operators and Their Effects

Choosing the right operator is critical for correctness and atomicity. The table below summarizes the most common operators and their behavior.

OperatorEffectExample
$setSets the value of a field{"$set": {"status": "active"}}
$unsetRemoves a field{"$unset": {"temp_field": ""}}
$incIncrements a numeric field by a given amount{"$inc": {"count": 1}}
$mulMultiplies a numeric field{"$mul": {"price": 1.1}}
$pushAppends a value to an array field{"$push": {"tags": "new"}}
$pullRemoves all matching values from an array{"$pull": {"tags": "obsolete"}}
$renameRenames a field{"$rename": {"old": "new"}}

When multiple operators appear in the same update document, MongoDB applies them in a single atomic operation. For example, you can increment a counter and update a timestamp together:

collection.update_one( {"_id": 1}, {"$inc": {"views": 1}, "$set": {"last_viewed": datetime.utcnow()}} )

This avoids the race condition that would occur if you issued two separate updates.

Bulk Write Operations with bulk_write()

For mixed sequences of updates and deletes, bulk_write() is the recommended approach. It accepts a list of write operations and executes them in a single round trip. Operations are instances of UpdateOne, UpdateMany, DeleteOne, or DeleteMany from pymongo.

from pymongo import UpdateOne, DeleteMany operations = [ UpdateOne({"sku": "ABC"}, {"$set": {"price": 24.99}}), UpdateMany({"category": "clearance"}, {"$mul": {"price": 0.7}}), DeleteMany({"status": "archived"}) ] result = collection.bulk_write(operations)

By default, bulk_write() executes operations in order and stops on the first error. This is called an ordered bulk write. If you pass ordered=False, MongoDB may reorder operations to improve performance, but you lose the guarantee that earlier operations complete before later ones. Use ordered bulk writes when operation order matters, such as when an update depends on a previous delete.

The result object contains counters like matched_count, modified_count, deleted_count, and upserted_count. These are useful for verifying that the expected number of documents were affected.

Handling Errors and Write Concerns

Write operations can fail for several reasons: network issues, duplicate key errors, or validation failures. PyMongo raises PyMongoError subclasses such as DuplicateKeyError, BulkWriteError, or OperationFailure. For bulk writes, BulkWriteError includes a details attribute with per-operation error information.

from pymongo.errors import BulkWriteError try: result = collection.bulk_write(operations) except BulkWriteError as e: print(f"Failed operations: {e.details['writeErrors']}")

Write concern controls how MongoDB acknowledges writes. The default acknowledges that the primary received the operation. For stronger durability, you can set w="majority" or a journaling option. This is done at the collection or client level, not per operation. In production, w="majority" is often preferred to avoid losing acknowledged writes during failover.

Performance and Batching Strategies

Individual update_one() or delete_one() calls each require a round trip to the server. When you need to modify many documents, using bulk_write() reduces network overhead and can dramatically improve throughput. However, very large batches (thousands of operations) can consume significant memory on the client and server. A common pattern is to chunk operations into batches of 500–1000.

def chunked_bulk_write(collection, operations, batch_size=500): for i in range(0, len(operations), batch_size): batch = operations[i:i+batch_size] collection.bulk_write(batch, ordered=False)

Unordered bulk writes allow MongoDB to parallelize independent operations, which can improve performance when order does not matter. But be aware that unordered writes do not guarantee that all operations succeed; if one fails, the others continue. Check the result to see how many succeeded.

Choosing the Right Approach for Your Workload

The decision between individual methods and bulk_write() depends on the number of operations and whether they are independent. For a single update or delete, use the dedicated method. For a few operations (say, less than 10) that must be ordered, individual calls are simpler and easier to read. For large batches of independent changes, bulk_write() with ordered=False is the most efficient choice.

Another consideration is atomicity. A single update_one() is atomic at the document level, but a sequence of separate updates is not. If you need all-or-nothing behavior across multiple documents, you must use a transaction (available with replica sets) or design your data model to avoid the need.

Finally, always check the result of write operations. The modified_count may be lower than matched_count if the update does not change any fields. This is normal and often indicates that the data already matches the desired state. Relying on modified_count for business logic can lead to subtle bugs, so prefer matched_count when you only need to know that the filter matched a document.

python pymongo update delete and bulk operations: Practical | RYUSLOG DEV