MongoDB's update operators are special $-prefixed keys used inside update documents to describe exactly how a document's fields should change â without needing to send the entire document back to the server. This tutorial covers every major category of update operator, from simple field assignment to advanced array manipulation and aggregation-style update pipelines.
Information
đ 1. Introduction
Instead of replacing a whole document, update operators let you target specific fields â incrementing a counter, pushing a value into an array, or renaming a field â in a single atomic operation.
Combining update operators
await collection.updateOne(
{ _id: productId },
{ $set: { price: 24.99 }, $inc: { views: 1 } }
);Note
đ§Š 2. Update Operations
Update operators are applied through updateOne(), updateMany(), findOneAndUpdate(), or as part of a bulkWrite() call. Each accepts a filter to select documents and an update document describing the changes.
đ§ 3. Field Update Operators
Field update operators modify scalar and document-level fields: setting values, removing fields, renaming, incrementing, and more.
$set
Sets the value of a field, creating it if it doesn't already exist.
Setting field values
await collection.updateOne(
{ name: "Mouse" },
{ $set: { price: 22.99, onSale: true } }
);$unset
Removes a field from a document entirely. The value passed is ignored â an empty string is conventional.
Removing a field
await collection.updateOne(
{ name: "Mouse" },
{ $unset: { discountCode: "" } }
);$rename
Renames a field, preserving its value.
Renaming a field
await collection.updateOne(
{ name: "Mouse" },
{ $rename: { qty: "stockCount" } }
);Warning
$inc
Increments (or decrements, with a negative value) a numeric field atomically.
Incrementing and decrementing fields
await collection.updateOne(
{ name: "Mouse" },
{ $inc: { stockCount: -1, views: 1 } }
);$mul
Multiplies a field's current value by the given number.
Multiplying a field value
// Apply a 10% price increase
await collection.updateOne(
{ name: "Mouse" },
{ $mul: { price: 1.1 } }
);$min / $max
$min updates a field only if the new value is less than the current value; $max only if it's greater than.
Conditional bounds with $min and $max
// Only updates if 15.99 is lower than the current lowestPrice
await collection.updateOne(
{ name: "Mouse" },
{ $min: { lowestPrice: 15.99 } }
);
// Only updates if 199.99 is higher than the current highestPrice
await collection.updateOne(
{ name: "Mouse" },
{ $max: { highestPrice: 199.99 } }
);$currentDate
Sets a field to the current date, either as a Date or a BSON timestamp.
Stamping the current date
await collection.updateOne(
{ name: "Mouse" },
{ $currentDate: { lastModified: true } }
);Tip
đ 12. Array Update Operators
Array update operators add, remove, or modify elements within array fields without needing to fetch and rewrite the entire array.
| Operator | Description |
|---|---|
| $push | Appends a value to an array |
| $pull | Removes all elements matching a condition |
| $pop | Removes the first or last element |
| $addToSet | Adds a value only if not already present |
| $pullAll | Removes all matching listed values |
$push
Appending to an array
// Append a single tag
await collection.updateOne(
{ name: "Mouse" },
{ $push: { tags: "wireless" } }
);
// Append multiple values with $each
await collection.updateOne(
{ name: "Mouse" },
{ $push: { tags: { $each: ["sale", "featured"] } } }
);$pull
Removing matching elements
// Remove exact value
await collection.updateOne(
{ name: "Mouse" },
{ $pull: { tags: "discontinued" } }
);
// Remove elements matching a condition
await collection.updateOne(
{ name: "Mouse" },
{ $pull: { reviews: { rating: { $lt: 2 } } } }
);$pop
Removes the first (-1) or last (1) element of an array.
Popping array elements
// Remove the last element
await collection.updateOne(
{ name: "Mouse" },
{ $pop: { tags: 1 } }
);
// Remove the first element
await collection.updateOne(
{ name: "Mouse" },
{ $pop: { tags: -1 } }
);$addToSet
Adds a value to an array only if it doesn't already exist, preventing duplicates.
Avoiding duplicate array values
await collection.updateOne(
{ name: "Mouse" },
{ $addToSet: { tags: "wireless" } }
);Tip
$pullAll
Removes all instances of each value in a given list, matching exact values only (no query conditions).
Removing a list of exact values
await collection.updateOne(
{ name: "Mouse" },
{ $pullAll: { tags: ["clearance", "old-stock"] } }
);đ¯ 18. Positional Operators
Positional operators target specific array elements within an update, rather than the array as a whole.
| Operator | Description |
|---|---|
| $ | Updates the first array element that matched the query filter |
| $[] | Updates all elements in the array |
| $[<identifier>] | Updates elements matching an arrayFilters condition |
Positional operators in action
// Update the rating of the first review that matches
await collection.updateOne(
{ _id: productId, "reviews.author": "Alice" },
{ $set: { "reviews.$.rating": 5 } }
);
// Set every review's "verified" flag to true
await collection.updateOne(
{ _id: productId },
{ $set: { "reviews.$[].verified": true } }
);Important
đ§Ž 19. Array Filters
The arrayFilters option, combined with the $[identifier] syntax, lets you update array elements matching custom conditions â independent of the top-level query filter.
Updating with arrayFilters
await collection.updateOne(
{ _id: productId },
{ $set: { "reviews.$[elem].flagged": true } },
{ arrayFilters: [{ "elem.rating": { $lte: 1 } }] }
);Example
đ 20. Upserts
An upsert creates a new document when no document matches the filter, applying the update operators to the new document as if it started empty.
Upsert with $setOnInsert
const result = await collection.updateOne(
{ sku: "SKU-2001" },
{ $set: { name: "Desk Lamp", price: 29.99 }, $setOnInsert: { createdAt: new Date() } },
{ upsert: true }
);Hint
đ 21. Replace Operations
Unlike operator-based updates, replaceOne() swaps out the entire document (except _id) rather than modifying individual fields.
Replacing an entire document
await collection.replaceOne(
{ name: "Mouse" },
{ name: "Wireless Mouse", price: 25.99, inStock: true }
);Danger
âī¸ 22. Bulk Updates
bulkWrite() lets you batch many updateOne, updateMany, and other operations into a single round-trip, significantly improving throughput.
Batching updates with bulkWrite()
await collection.bulkWrite([
{
updateOne: {
filter: { name: "Mouse" },
update: { $inc: { stockCount: -1 } }
}
},
{
updateMany: {
filter: { inStock: false },
update: { $set: { discontinued: true } }
}
}
]);đ§ 23. Update Pipelines
Since MongoDB 4.2, updates can use an aggregation pipeline (an array of stages) instead of a plain update document, unlocking expressions that reference the document's own fields.
Using an update pipeline
await collection.updateOne(
{ name: "Mouse" },
[
{ $set: { finalPrice: { $multiply: ["$price", 0.9] } } },
{ $set: { updatedAt: "$$NOW" } }
]
);Reference
⥠24. Performance Optimization
- Ensure the filter portion of an update is covered by an index to avoid a full collection scan.
- Prefer $inc over read-modify-write patterns to avoid race conditions and extra round-trips.
- Batch related updates with bulkWrite() instead of looping individual updateOne() calls.
- Use arrayFilters instead of fetching, mutating, and replacing entire arrays client-side.
đ 25. Best Practices
- Always use $set for partial field updates instead of replaceOne().
- Use $setOnInsert alongside upsert: true to safely initialize fields only on creation.
- Prefer $addToSet over $push when array values must remain unique.
- Name arrayFilters identifiers descriptively (e.g. elem, review) for readability.
- Test update pipelines on a sample document before running them against production data.
â ī¸ 26. Common Mistakes
- Mixing update operators and plain fields in the same update document, which MongoDB rejects.
- Forgetting that the $ positional operator only updates the first matching array element.
- Using $push when $addToSet was intended, resulting in duplicate array entries.
- Omitting arrayFilters when using the $[identifier] syntax, causing an error.
- Accidentally using replaceOne() instead of updateOne(), wiping out unspecified fields.
Best Practice
â 27. Frequently Asked Questions
Yes. If the target field doesn't already exist, $set creates it with the given value.
Yes. A single update document can combine multiple operators, such as $set, $inc, and $push, as long as they don't target the same field.
Yes. $inc is applied atomically at the document level, making it safe for concurrent increments like counters.