Skip to main content

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

javascript
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:

javascript
// Without any documents matching "P1001"
db.products.updateOne(
{ product_id: "P1001" },
{ $set: { name: "Smartphone", price: 499.99 } },
{ upsert: true }
)

Output:

javascript
{
"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:

javascript
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().

javascript
db.collection.updateMany(
<filter>,
<update>,
<options>
)

Example: Updating Multiple Documents

javascript
// Update all products with price less than 100
db.products.updateMany(
{ price: { $lt: 100 } },
{ $mul: { price: 1.1 } } // Increase prices by 10%
)

Output:

javascript
{
"acknowledged": true,
"matchedCount": 5,
"modifiedCount": 5
}

Write Concern

Write concern describes the level of acknowledgment requested from MongoDB for write operations.

javascript
db.collection.updateOne(
<filter>,
<update>,
{
writeConcern: <document>
}
)

Example: Using Write Concern

javascript
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.

javascript
db.collection.updateOne(
<filter>,
<update>,
{
collation: {
locale: <string>,
caseLevel: <boolean>,
// other collation options...
}
}
)

Example: Case-Insensitive Update

javascript
// 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.

javascript
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:

javascript
// 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:

javascript
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.

javascript
db.collection.findOneAndUpdate(
<filter>,
<update>,
{
returnDocument: <string> // "before" or "after"
}
)

Example: Return Updated Document

javascript
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:

javascript
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:

javascript
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:

  1. Updates settings if the user already has a record
  2. Creates settings if no record exists
  3. Sets a creation timestamp only for new records
  4. Always updates the last_modified field

Bulk Write with Different Options

MongoDB allows you to perform bulk operations with different options:

javascript
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:

  1. Indexes matter: Ensure your filter fields are indexed, especially for large collections.
  2. Write concern balance: Higher levels of write concern (like majority) provide more durability but at the cost of performance.
  3. Avoid updating unnecessary fields: Only include fields that need updating to minimize overhead.
  4. 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:

javascript
// 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:

javascript
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

  1. 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.

  2. Create a function that safely increments a counter field, ensuring the document exists first (hint: use upsert).

  3. Write an update operation that modifies only weekend dates in an array of event dates.

  4. 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! :)