3.3 Document Replacement & Deletion Operations

Key Takeaways

  • replaceOne() replaces the entire content of a matching document while automatically preserving the existing _id.
  • The replacement document in replaceOne() cannot contain atomic update operators like $set or $inc; passing update operators throws an immediate runtime error.
  • deleteOne() deletes the first matching document, whereas deleteMany() deletes all documents matching the filter condition.
  • deleteMany({}) removes documents one-by-one, maintaining indexes and generating oplog delete entries for each document.
  • db.collection.drop() drops the entire collection and all its indexes instantly at the storage catalog level, providing vastly superior performance for complete data wipes.
Last updated: September 2026

3.3 Document Replacement & Deletion Operations

While field-level update operators modify selected portions of a document, MongoDB also provides document replacement and deletion primitives. replaceOne() swaps out an entire document while preserving its primary key (_id), while deleteOne() and deleteMany() remove documents based on query filter criteria. Understanding how these operations interact with storage engines, indexes, replication oplogs, and sharded environments is a core competency for developers.


1. Document Replacement: replaceOne()

db.collection.replaceOne(filter, replacement, options) completely replaces the existing document matching the query filter with a new replacement document.

db.users.replaceOne(
  { _id: 105 }, // Filter matching the target document
  {
    name: "Taylor Morgan",
    email: "tmorgan@example.com",
    tier: "platinum",
    updatedAt: new Date()
  }, // Replacement document (entire new document body)
  {
    upsert: true,
    writeConcern: { w: "majority", wtimeout: 5000 }
  } // Options document
);

Critical Rules of replaceOne()

  1. Preservation of _id: The _id field is immutable in MongoDB. If the replacement document does not specify _id, MongoDB retains the original document's _id. If the replacement document explicitly includes an _id, its value must exactly match the existing document's _id, or MongoDB throws an ImmutableField or duplicate key error.
  2. Total Field Overwrite: Any fields in the old document that are omitted from the replacement document are permanently removed. The replacement document completely supplants the old document's state.
  3. Prohibition of Update Operators: The replacement argument must consist solely of <field>: <value> pairs. It cannot contain atomic update operators (such as $set, $unset, or $inc).
// ERROR EXAMPLE: Passing $set into replaceOne throws an immediate exception
db.users.replaceOne(
  { _id: 105 },
  { $set: { tier: "platinum" } } // MongoServerError: Replacement document must not contain atomic operators
);

replaceOne() Return Document

{
  acknowledged: true,
  matchedCount: 1,
  modifiedCount: 1,
  upsertedId: null,
  upsertedCount: 0
}

Schema Validation and Sharding Rules for replaceOne()

  • JSON Schema Validation: When collection validation rules (validator: { $jsonSchema: ... }) are configured, MongoDB validates the replacement document in its entirety. Because replaceOne() replaces the whole document, the replacement payload must satisfy all required fields specified by the schema validator, regardless of whether validationLevel is set to "strict" or "moderate".
  • Sharded Collections: In a sharded cluster, executing replaceOne() requires that the query filter includes an exact equality match on the shard key. If the shard key is omitted from the filter in a sharded collection, MongoDB throws a targeting error.

2. Document Deletion Methods: deleteOne() & deleteMany()

MongoDB provides two dedicated methods for deleting documents from a collection:

2.1 deleteOne(filter, options)

Deletes the first document that matches the query filter according to natural storage order or index traversal.

db.orders.deleteOne(
  { orderId: "ORD-8821", status: "CANCELLED" },
  { writeConcern: { w: "majority" } }
);

2.2 deleteMany(filter, options)

Deletes all documents in the collection that satisfy the query filter.

db.sessions.deleteMany(
  { expiresAt: { $lt: new Date() } },
  { writeConcern: { w: 1 } }
);

Deletion Options and Return Document

Both deleteOne() and deleteMany() accept options controlling execution:

  • writeConcern: Specifies the acknowledgment level (e.g., { w: "majority", wtimeout: 5000 }).
  • collation: Specifies locale-sensitive string matching rules for the filter.
  • hint: Specifies an index name or index specification document to force an index scan for the filter.
{
  acknowledged: true,
  deletedCount: 14
}
PropertyTypeMeaning
acknowledgedBooleantrue if executed with a recognized write concern; false if unacknowledged (w: 0).
deletedCountIntegerThe exact number of documents removed from the collection.

Exam Trap: Passing an empty filter {} to deleteOne({}) will delete the first document encountered in the collection. Passing an empty filter {} to deleteMany({}) will delete every document in the collection.


3. Deep Architectural Comparison: deleteMany({}) vs. db.collection.drop()

When a developer needs to clear an entire collection (for instance, during an environment reset, batch reprocessing, or test cleanup), MongoDB offers two distinct approaches: executing db.collection.deleteMany({}) or invoking db.collection.drop(). Although both result in zero documents in the collection, their underlying architectural behaviors differ drastically across the storage engine, indexing subsystem, replication oplog, and filesystem.

// Approach A: Document-level bulk wipe
db.logs.deleteMany({});

// Approach B: Catalog-level collection drop
db.logs.drop();

Architectural Comparison Matrix

Architectural Dimensiondb.collection.deleteMany({})db.collection.drop()
Storage MechanismIterates through every document individually, deleting records one by one in the WiredTiger storage engine.Drops the entire underlying table and metadata in WiredTiger in a single catalog operation.
Index HandlingPreserves all indexes. Traverses every index B-tree to delete individual keys, leaving empty index structures in place.Drops all indexes associated with the collection immediately along with the collection tables.
Collection MetadataPreserves collection metadata, options, JSON Schema validators, and collation settings.Deletes all collection metadata from the database catalog (system.views and catalog tables).
Replication & Oplog ImpactGenerates an individual delete entry in the oplog.rs for every single deleted document (massive oplog churn and network bandwidth consumption).Generates a single drop command entry in the oplog.rs.
Storage ReclamationReclaims document space inside WiredTiger data files as free space for future MongoDB writes, but does not return space to the OS filesystem.Immediately frees the underlying data and index files on disk, returning storage blocks to the filesystem.
Performance Complexity$O(N)$ where $N$ is the number of documents + total index entries. Extremely slow for millions of records.$O(1)$ catalog metadata update. Near instantaneous regardless of collection size.

When to Use Which Method in Production

  • Use deleteMany({}) when:
    • You must preserve custom indexes and collection configuration (e.g., schema validation rules, collation settings) so that incoming application writes can continue immediately without re-indexing.
    • You are deleting a subset of data matching a filter (e.g., { tenantId: "demo" }).
  • Use db.collection.drop() when:
    • You want to wipe an entire large dataset quickly without incurring severe oplog replication lag, CPU spikes, or B-tree lock contention.
    • Note: You must recreate any non-default indexes if your application subsequently writes new data to the collection name.

4. replaceOne() vs. updateOne() Summary

Featuredb.collection.replaceOne()db.collection.updateOne()
Payload StructureComplete document body ({ name: "Alex", role: "admin" }).Update operators ({ $set: { role: "admin" } }) or pipeline.
Update Operators Permitted?No (Throws MongoServerError).Yes (Required).
Omitted FieldsOmitted fields are deleted from the document.Omitted fields are preserved untouched.
Primary Key (_id)Preserved from original doc, or must match exactly if supplied.Preserved automatically.
Loading diagram...
Architectural Pipeline: deleteMany({}) vs db.collection.drop()
Test Your Knowledge

A developer runs the following command: db.inventory.replaceOne({ _id: 50 }, { $set: { quantity: 100, status: "IN_STOCK" } }); What is the outcome of this operation?

A
B
C
D
Test Your Knowledge

An existing document in the 'customers' collection is: { _id: 200, name: "Alice", phone: "555-0100", tier: "Gold", loyaltyPoints: 450 }. A developer executes: db.customers.replaceOne({ _id: 200 }, { name: "Alice Smith", email: "alice@example.com" }); What is the final state of the document in the database?

A
B
C
D
Test Your Knowledge

A production database administrator needs to completely purge 50 million old log records from a collection on a busy replica set. Why is db.collection.drop() preferred over db.collection.deleteMany({}) for this task?

A
B
C
D
Test Your Knowledge

What is the result of executing db.orders.deleteOne({}) on a collection containing 100 documents?

A
B
C
D