Introduction
MongoDB is a powerful NoSQL database often used for its flexibility and performance. Updating records in MongoDB, in specific updating a field based on its existing value, is a common operation, and there are several methods to achieve this. This tutorial will explore various ways in which you can update a document’s field based on the current value of that field, complete with examples ranging from basic to advanced.
Basic Update with $set
Before we jump into updating fields based on their current values, let’s review the basic update operation using the $set
operator. Assume we have a collection named users
containing user documents that look like this:
{
"_id": ObjectId("507f191e810c19729de860ea"),
"name": "John Doe",
"age": 28
}
To simply change the age of a user you would use:
db.users.updateOne(
{ "name": "John Doe" },
{ "$set": { "age": 30 } }
);
This statement would set John Doe’s age to 30. Now let’s see how to increment the current age by 2:
Incrementing a Field
Using the $inc
operator, we can update a field based on its current value. To increment John’s age by 2, we could write:
db.users.updateOne(
{ "name": "John Doe" },
{ "$inc": { "age": 2 } }
);
This update operation reads the current value of the age
field and adds 2 to it, updating the document accordingly.
Conditionally Updating a Field
What if we want to update the age only if it’s below a certain threshold? That requires the combination of a query filter and the update:
db.users.updateOne(
{ "name": "John Doe", "age": { "$lt": 30 } },
{ "$set": { "age": 30 } }
);
In this instance, if John Doe is younger than 30, his age is set to 30. If he is 30 or older, the document is not updated.
Using $mul
to Update a Field
If instead of adding a static number to a field, you want to multiply a field by a given number, you’d use the $mul
operator. Suppose we want to double the age:
db.users.updateOne(
{ "name": "John Doe" },
{ "$mul": { "age": 2 } }
);
After this operation, if John’s initial age was 28, it would now be 56.
Advanced Updates Using Aggregation Pipeline
With the advent of MongoDB 4.2 and later versions, you can pass an aggregation pipeline to the updateOne()
or updateMany()
functions. This allows for complex computations and conditional updates based on the current value of the field.
Here’s an example where we cap the age at 50, but if the age is under 30, we increment by 10>:
db.users.updateOne(
{ "name": "John Doe" },
[{
"$set": {
"age": {
"$cond": {
"if": { "$lt": ["$age", 30] },
"then": { "$add": ["$age", 10] },
"else": { "$min": ["$age", 50] }
}
}
}
}]
);
This uses the $cond
operator to determine whether to add 10 to the age or simply set it to 50, depending on the starting value of age.
Updating Fields Based on Other Fields
In certain cases, fields within the same document are dependent on each other. For example, suppose our users
documents also have a birthdate
and we want to set the age
field based on the birthdate
. Here’s an example using the $dateDiff
operator available in MongoDB 5.0 and newer versions:
db.users.updateMany(
{},
[{
"$set": {
"age": {
"$floor": {
"$divide": [
{ "$dateDiff": {
"startDate": "$birthdate",
"endDate": "$currentDate",
"unit": "year"
} },
1
] }
}
}
}
}]
);
This pipeline updates the age of all users in the collection based on their birthdates. It calculates the difference in years between the current date and their birthdate and then sets the age accordingly.
Conclusion
The versatility of MongoDB’s update operations allows for precise manipulation of document fields. We’ve seen the capability of simple updates with operators like $set
and $inc
, as well as complex computations with the aggregation pipeline for conditional updates and inter-field dependencies. Use these powerful tools to ensure your data stays accurate and up-to-date.