MongoDB Delete
Learn how to delete documents from MongoDB in Python using PyMongo's delete_one() and delete_many() with filters, error handling, and safe patterns.
PyMongo provides two methods for removing documents from a collection: delete_one() removes the first matching document, and delete_many() removes every matching document. Both are precise, filter-driven operations — you specify exactly which documents to target using the same query syntax as find().
This chapter covers:
delete_one()— remove a single documentdelete_many()— remove multiple documents (including all documents)- Reading the
DeleteResultobject - Filter operators that make deletions precise
- Error handling and safety practices
- When to delete documents versus dropping the whole collection
Prerequisites: Python 3.8+, PyMongo installed (
pip install pymongo), and a running MongoDB server. See MongoDB Get Started for setup, and MongoDB Insert to understand how documents get into a collection in the first place.
Connecting and Selecting a Collection
Every delete operation needs a MongoClient, a database, and a collection:
import pymongo
client = pymongo.MongoClient("mongodb://localhost:27017/")
db = client["mydatabase"]
col = db["customers"]All examples below assume col is defined this way.
Deleting One Document with delete_one()
delete_one(filter) finds the first document that matches the filter and deletes it. If multiple documents match, only one is removed (MongoDB's natural order determines which one).
result = col.delete_one({"name": "Alice"})
print(result.deleted_count) # 1 if a match was found, 0 if notdelete_one() never raises an error when no document matches — it returns a DeleteResult with deleted_count = 0.
Matching on a specific field value
# Delete the customer whose name is "Bob"
result = col.delete_one({"name": "Bob"})
if result.deleted_count == 1:
print("Document deleted.")
else:
print("No matching document found.")Matching on a nested field
Use dot notation to target fields inside embedded documents:
# Delete the first customer whose city is "London"
result = col.delete_one({"address.city": "London"})
print(result.deleted_count) # 1 or 0Deleting Multiple Documents with delete_many()
delete_many(filter) removes every document that matches the filter. Use it when you need to clean up a set of records in one call.
# Delete all customers whose address starts with "S"
result = col.delete_many({"address": {"$regex": "^S"}})
print(result.deleted_count, "documents deleted")Deleting all documents in a collection
Pass an empty filter {} to remove every document. The collection itself and its indexes remain — only the documents are gone:
result = col.delete_many({})
print(result.deleted_count, "documents deleted")Warning:
delete_many({})on a production collection is irreversible. Always double-check your filter and take a backup before running bulk deletes. If you want to remove the collection entirely (documents and indexes), usecol.drop()— see MongoDB Drop Collection.
The DeleteResult Object
Both methods return a DeleteResult. The two properties you will use most often are:
| Property | Type | Description |
|---|---|---|
deleted_count | int | Number of documents actually deleted |
acknowledged | bool | True if the server confirmed the write; False for unacknowledged writes |
result = col.delete_many({"status": "inactive"})
print(f"Deleted: {result.deleted_count}")
print(f"Acknowledged: {result.acknowledged}")Filter Operators for Precise Deletions
The same query operators used in find() work inside delete filters.
Delete by comparison
# Delete all orders with a quantity less than 10
col.delete_many({"qty": {"$lt": 10}})
# Delete all orders with a quantity greater than or equal to 100
col.delete_many({"qty": {"$gte": 100}})Delete by regular expression
# Delete all customers whose name starts with "A" (case-sensitive)
col.delete_many({"name": {"$regex": "^A"}})Delete by existence of a field
# Delete all documents that have no "email" field
col.delete_many({"email": {"$exists": False}})Delete by value in a list
# Delete all documents whose status is either "cancelled" or "expired"
col.delete_many({"status": {"$in": ["cancelled", "expired"]}})Error Handling
Wrap delete operations in a try/except block to handle the two most common failure modes:
pymongo.errors.OperationFailure— the server rejected the operation (e.g., the connected user lacksremoveprivileges on the collection).pymongo.errors.ConnectionFailure— the network connection to MongoDB was lost.
import pymongo
client = pymongo.MongoClient("mongodb://localhost:27017/")
col = client["mydatabase"]["customers"]
try:
result = col.delete_many({"status": "inactive"})
print(f"{result.deleted_count} documents deleted.")
except pymongo.errors.OperationFailure as e:
print(f"Server error: {e}")
except pymongo.errors.ConnectionFailure as e:
print(f"Connection error: {e}")Practical Example: Full Workflow
This example seeds a collection, runs targeted deletes, and verifies the outcome:
import pymongo
client = pymongo.MongoClient("mongodb://localhost:27017/")
col = client["mydatabase"]["customers"]
# 1. Start clean
col.drop()
# 2. Insert sample documents
col.insert_many([
{"name": "Alice", "city": "Oslo", "active": True},
{"name": "Bob", "city": "Sydney", "active": False},
{"name": "Carol", "city": "Seattle","active": False},
{"name": "Dave", "city": "Sofia", "active": True},
])
print("Inserted:", col.count_documents({})) # 4
# 3. Delete the one inactive customer named "Bob"
r1 = col.delete_one({"name": "Bob", "active": False})
print("delete_one:", r1.deleted_count) # 1
# 4. Delete all customers in cities that start with "S"
r2 = col.delete_many({"city": {"$regex": "^S"}})
print("delete_many (city ^S):", r2.deleted_count) # 2 (Carol/Seattle, Dave/Sofia)
# 5. Check what remains
remaining = list(col.find({}, {"_id": 0}))
print("Remaining:", remaining) # [{'name': 'Alice', 'city': 'Oslo', 'active': True}]Expected output:
Inserted: 4
delete_one: 1
delete_many (city ^S): 2
Remaining: [{'name': 'Alice', 'city': 'Oslo', 'active': True}]Delete Documents vs. Drop a Collection
These two operations are frequently confused:
| Operation | Documents removed | Collection removed | Indexes removed | Speed |
|---|---|---|---|---|
col.delete_many({}) | All | No | No | Slower on large sets |
col.drop() | All | Yes | Yes | Very fast |
Choose delete_many({}) when you need to empty a collection but keep its indexes and schema validators intact. Choose col.drop() when you want a completely clean slate — for example, between test runs or during a schema migration. See MongoDB Drop Collection for details on drop().
Summary
delete_one(filter)removes the first matching document;delete_many(filter)removes all matching documents.- Both return a
DeleteResult— checkdeleted_countto confirm what was removed. - An empty filter
{}indelete_many()removes all documents from the collection. - Use MongoDB query operators (
$regex,$lt,$in,$exists, …) to build precise filters. - Wrap operations in
try/exceptto handleOperationFailureandConnectionFailure. - To remove the collection itself, use
col.drop()instead.
Related chapters:
- MongoDB Insert — inserting documents with
insert_one()andinsert_many() - MongoDB Update — modifying existing documents with
update_one()andupdate_many() - MongoDB Drop Collection — removing an entire collection including its indexes
- MongoDB Query — building filters with query operators
- MongoDB Get Started — installing PyMongo and connecting to MongoDB