MongoDB Update Options
When updating documents in MongoDB, you have several options that control how the update operation behaves. These options provide flexibility and precision in how your updates are applied to your database.
Introduction
MongoDB's update operations (updateOne()
, updateMany()
, and findAndModify()
) accept a set of options that modify their behavior beyond the basic update functionality. These options let you:
- Create new documents if matching ones don't exist
- Update multiple documents in a single operation
- Control the write acknowledgment process
- Return specific information about the updated documents
- And more!
Understanding these options will help you write more efficient and powerful MongoDB operations.
Common Update Options
The Upsert Option
The upsert
option is one of the most commonly used update options. When set to true
, it creates a new document if no document matches the query criteria.
Syntax
db.collection.updateOne(
<filter>,
<update>,
{ upsert: <boolean> }
)
Example: Basic Upsert
Let's say we have a products collection and want to update a product with ID "P1001", but we're not sure if it exists yet:
// Without any documents matching "P1001"
db.products.updateOne(
{ product_id: "P1001" },
{ $set: { name: "Smartphone", price: 499.99 } },
{ upsert: true }
)
Output:
{
"acknowledged": true,
"matchedCount": 0,
"modifiedCount": 0,
"upsertedId": ObjectId("5f7b1a9e9d3b2c1a2b3c4d5e")
}
Notice that matchedCount
is 0 (no documents matched), but a new document was created with the ID shown in upsertedId
.
Example: Upsert with Update Operators
Upsert becomes even more powerful when combined with update operators:
db.inventory.updateOne(
{ item: "sketch pad" },
{
$set: { qty: 25, tags: ["art", "supplies"] },
$currentDate: { lastModified: true }
},
{ upsert: true }
)
If the item "sketch pad" doesn't exist, MongoDB creates a new document containing all the fields in the update operation, plus the _id
and item
fields.
Multi-Update Option
In MongoDB, the updateOne()
method updates a single document by default. To update multiple documents matching your filter, you need to use updateMany()
.
db.collection.updateMany(
<filter>,
<update>,
<options>
)
Example: Updating Multiple Documents
// Update all products with price less than 100
db.products.updateMany(
{ price: { $lt: 100 } },
{ $mul: { price: 1.1 } } // Increase prices by 10%
)
Output:
{
"acknowledged": true,
"matchedCount": 5,
"modifiedCount": 5
}
Write Concern
Write concern describes the level of acknowledgment requested from MongoDB for write operations.
db.collection.updateOne(
<filter>,
<update>,
{
writeConcern: <document>
}
)
Example: Using Write Concern
db.orders.updateOne(
{ order_id: "12345" },
{ $set: { status: "shipped" } },
{
writeConcern: { w: "majority", wtimeout: 5000 }
}
)
This operation will:
- Wait for acknowledgment from a majority of replica set members
- Time out after 5000 milliseconds if adequate acknowledgment isn't received
Collation Option
Collation allows you to specify language-specific rules for string comparison.
db.collection.updateOne(
<filter>,
<update>,
{
collation: {
locale: <string>,
caseLevel: <boolean>,
// other collation options...
}
}
)
Example: Case-Insensitive Update
// Update user regardless of case in username
db.users.updateOne(
{ username: "john_doe" },
{ $set: { status: "active" } },
{
collation: { locale: "en", strength: 2 } // Case-insensitive
}
)
This will match documents with username values like "john_doe", "John_Doe", "JOHN_DOE", etc.
arrayFilters
The arrayFilters
option allows you to update specific elements within arrays.
db.collection.updateOne(
<filter>,
<update>,
{ arrayFilters: [ <filterdocument1>, ... ] }
)
Example: Updating Specific Array Elements
Let's say we have a students collection with grades for different subjects:
// Sample document
{
_id: 1,
name: "Alice",
grades: [
{ subject: "math", score: 85 },
{ subject: "english", score: 92 },
{ subject: "science", score: 78 }
]
}
To increase all failing grades (below 80) by 5 points:
db.students.updateOne(
{ _id: 1 },
{ $inc: { "grades.$[element].score": 5 } },
{ arrayFilters: [ { "element.score": { $lt: 80 } } ] }
)
Result: Only the science score will be increased to 83, while math and english remain unchanged.
returnDocument Option
When using findOneAndUpdate()
, you can specify whether to return the document before or after the update.
db.collection.findOneAndUpdate(
<filter>,
<update>,
{
returnDocument: <string> // "before" or "after"
}
)
Example: Return Updated Document
const result = db.products.findOneAndUpdate(
{ product_id: "P1001" },
{ $inc: { stock: -1 } },
{ returnDocument: "after" }
)
console.log(result) // Shows the document after stock was decremented
Real-World Applications
Inventory Management System
Let's build a simple inventory management system that uses update options effectively:
function processOrder(productId, quantity) {
// Update stock and track order in one operation
const result = db.products.findOneAndUpdate(
{ product_id: productId, stock: { $gte: quantity } },
{
$inc: { stock: -quantity },
$push: {
orders: {
date: new Date(),
quantity: quantity
}
}
},
{
returnDocument: "after"
}
);
if (result) {
console.log(`Order processed. Remaining stock: ${result.stock}`);
return true;
} else {
console.log("Order failed - insufficient stock");
return false;
}
}
User Settings with Upsert
For applications where you want to ensure user settings always exist:
function saveUserSettings(userId, settings) {
return db.settings.updateOne(
{ user_id: userId },
{
$set: settings,
$setOnInsert: { created_at: new Date() },
$currentDate: { last_modified: true }
},
{ upsert: true }
);
}
// Usage
saveUserSettings("user123", {
theme: "dark",
notifications: true,
language: "en"
});
This function:
- Updates settings if the user already has a record
- Creates settings if no record exists
- Sets a creation timestamp only for new records
- Always updates the last_modified field
Bulk Write with Different Options
MongoDB allows you to perform bulk operations with different options:
db.products.bulkWrite([
{
updateOne: {
filter: { item: "paper" },
update: { $inc: { stock: 100 } },
upsert: true
}
},
{
updateMany: {
filter: { category: "office" },
update: { $set: { department: "stationery" } }
}
},
{
updateOne: {
filter: { item: "planner" },
update: { $inc: { popularity: 1 } },
arrayFilters: [{ "qty": { $lt: 20 } }]
}
}
], { ordered: false });
This performs multiple write operations with different update options in a single database request.
Performance Considerations
When using update options, keep these performance tips in mind:
- Indexes matter: Ensure your filter fields are indexed, especially for large collections.
- Write concern balance: Higher levels of write concern (like
majority
) provide more durability but at the cost of performance. - Avoid updating unnecessary fields: Only include fields that need updating to minimize overhead.
- Bulk operations: Group related updates with
bulkWrite()
for better performance.
Common Mistakes and Troubleshooting
Mistake 1: Using $set
with Upsert Incorrectly
When using upsert, remember that MongoDB only includes the filter field if it's not using an operator expression:
// This creates a document without a "name" field
db.users.updateOne(
{ name: { $eq: "John" } },
{ $set: { age: 30 } },
{ upsert: true }
)
// Better approach to ensure "name" is included
db.users.updateOne(
{ name: "John" },
{ $set: { age: 30 } },
{ upsert: true }
)
Mistake 2: Forgetting to Check Result
Always check the result of update operations:
const result = db.products.updateOne(
{ _id: productId },
{ $set: updatedData }
);
if (result.matchedCount === 0) {
console.log("No documents matched the filter. Update failed.");
}
if (result.modifiedCount === 0 && result.matchedCount > 0) {
console.log("Document matched but nothing was changed.");
}
Summary
MongoDB update options provide powerful capabilities for controlling how your update operations behave:
- Upsert: Creates new documents when no matches exist
- Multi-document updates: Change multiple documents with one command
- Write concern: Control acknowledgment requirements for reliability
- Collation: Apply language-specific string comparison rules
- arrayFilters: Target specific elements within arrays
- returnDocument: Control which version of a document is returned
Mastering these options will help you write more efficient, precise, and powerful MongoDB operations that can handle a wide variety of real-world scenarios.
Practice Exercises
-
Write an update operation that increases the price of all products in the "electronics" category by 5%, but only if they currently cost less than $500.
-
Create a function that safely increments a counter field, ensuring the document exists first (hint: use upsert).
-
Write an update operation that modifies only weekend dates in an array of event dates.
-
Build an update operation that changes the status of all "pending" tasks to "in progress", but makes sure to update the "modified_date" field and returns the updated documents.
Additional Resources
If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)