Browse documentation
MongoDB TutorialVerified with mongodb 7.5.0

MongoDB updateMany and Delete Query Examples

Use MongoDB updateOne, updateMany, replace, upsert, find-and-modify, and delete examples with precise filters, result checks, and safer write practices.

Prepare safe tutorial records

MongoDB writes use a filter to select documents. A precise filter is the most important safety control in an update or delete script. Start with records marked for this tutorial:

use("mongog_tutorial");
const tasks = db.collection("tasks");

tasks.deleteMany({ tutorial: "writes" });
tasks.insertMany([
  { title: "Review schema", status: "open", priority: 2, labels: ["database"], tutorial: "writes" },
  { title: "Add index", status: "open", priority: 3, labels: ["performance"], tutorial: "writes" },
  { title: "Archive sample", status: "done", priority: 1, labels: [], tutorial: "writes" },
]);

Update fields with operators

updateOne() changes the first matching document. The update document normally uses operators such as $set, $inc, $push, and $unset:

const result = tasks.updateOne(
  { title: "Review schema", tutorial: "writes" },
  {
    $set: { status: "in-progress", updatedAt: ISODate() },
    $inc: { priority: 1 },
    $addToSet: { labels: "active" },
  },
);

printjson(result);
tasks.findOne({ title: "Review schema", tutorial: "writes" });

The result distinguishes matchedCount from modifiedCount. A document can match without being modified when the requested values are already present.

Update many documents

updateMany() applies the same update to every match. Preview the filter with find() or countDocuments() before an important bulk write:

const filter = { status: "open", tutorial: "writes" };
const candidates = tasks.countDocuments(filter);
print("Documents to update:", candidates);

tasks.updateMany(filter, {
  $set: { reviewed: false },
  $currentDate: { updatedAt: true },
});

tasks.find(filter).sort({ title: 1 });

For production maintenance, also consider server roles, backups, and a filter that includes a stable tenant or application boundary.

Use upsert intentionally

An upsert updates a match or inserts a new document when no match exists. It is useful for configuration and idempotent synchronization:

tasks.updateOne(
  { externalId: "task-900", tutorial: "writes" },
  {
    $set: { title: "Synced task", status: "open", updatedAt: ISODate() },
    $setOnInsert: { createdAt: ISODate(), tutorial: "writes" },
  },
  { upsert: true },
);

Back the logical identity with a unique index when concurrent writers could attempt the same upsert.

Delete with a verified filter

Use deleteOne() for one match and deleteMany() for a set. Count or display candidates first:

const archiveFilter = { status: "done", tutorial: "writes" };
print("Documents to delete:", tasks.countDocuments(archiveFilter));
tasks.find(archiveFilter, { projection: { title: 1, status: 1 } });

After reviewing the result, run the delete:

const deleted = tasks.deleteMany({ status: "done", tutorial: "writes" });
print("Deleted:", deleted.deletedCount);
tasks.find({ tutorial: "writes" }).sort({ title: 1 });

Expected result

The update result reports matched and modified counts. The final query contains the two non-archived tutorial tasks and no unrelated records are affected.

Update array elements precisely

Array update operators prevent a script from reading, changing, and replacing the entire array. The positional $ operator targets the first matched element, while filtered positional identifiers can update every element that meets a condition:

await tasks.updateOne(
  { title: "Review schema", tutorial: "writes" },
  {
    $set: {
      "checklist.$[item].done": true,
      updatedAt: ISODate(),
    },
  },
  {
    arrayFilters: [{ "item.label": "Read validator" }],
  },
);

Only use this after the document contains a checklist array of embedded documents. Keep array filters as specific as the write itself and inspect matchedCount plus modifiedCount.

Use find-and-modify when the new value is needed

findOneAndUpdate() can select and update one document as a single server operation, then return the pre-update or post-update value:

const claimed = await tasks.findOneAndUpdate(
  { status: "open", tutorial: "writes" },
  {
    $set: { status: "in-progress", claimedAt: ISODate() },
  },
  {
    sort: { priority: -1, _id: 1 },
    returnDocument: "after",
  },
);

printjson(claimed);

The operation is atomic for the selected document. Use a deterministic sort when multiple candidates can match, and add an index that supports the filter and selection order for a real work queue.

Design deletion as a lifecycle

Permanent deletion is not the only model. Some systems first set deletedAt, remove the record from ordinary queries, and purge it later under a retention policy. This supports recovery and audit needs but requires every normal query to honor the lifecycle field.

Practice by adding three checklist elements to a tutorial task, updating one with arrayFilters, claiming the highest-priority open task, and implementing a soft-delete field. Finish with a verification query that makes active and deleted records explicit.

Common mistakes

  • An empty filter such as {} matches every document. Never use it for a write unless deleting or updating the entire collection is explicitly intended.
  • Passing a plain replacement-shaped object to an update method is different from using update operators. Use replaceOne() only when full replacement is intentional.
  • Assuming an upsert cannot duplicate a logical record ignores concurrent writers. Enforce unique business keys with an index.
  • Treating MongoG's read-only scan as an authorization boundary is unsafe. It is best-effort; server-side MongoDB roles are authoritative.
  • Running find() and then updateOne() as separate claim steps can race; use a suitable atomic find-and-modify operation.
  • Adding a soft-delete field without updating every normal access path can expose records the application considers deleted.

Continue learning

Build the target set with the MongoDB query examples, then transform and summarize records with aggregation pipelines. The official driver documentation covers update and delete operations.