Reputation: 241
I want to update field in exists mongodb document. But set value should be average value of old value and new value.
I can get old value from mongodb document and calculate average value, and set into field, but it's not thread safety and old value in mongodb document might change while I calculate average.
Example, document:
{ '_id': ObjectId("55d49338b9796c337c894df3"), value: 10 }
Python code:
# new_value = 15, therefore average_value = 12.5
db.mycollection.update_one(
{'_id': '55d49338b9796c337c894df3'},
{...} <- What there?
)
Before:
{ '_id': ObjectId("55d49338b9796c337c894df3"), value: 12.5 }
Upvotes: 1
Views: 1198
Reputation: 103445
You can use the aggregation framework to do update. The pipeline steps you need for this are $addFields
and $out
. The $addFields
operator allows you to replace an existing fields within the collection with results from
an expression, which would involve the arithmetic operator $avg
to compute the average.
The $avg
operator, if used in the $project
(or $addFields
) stage, can accept a list of expressions and with that list you can push values from the existing field and the new value for computing the average
of these two.
The $out
operator as the final stage will update the existing collection as it writes the resulting documents of the aggregation pipeline to a collection.
The following example describes the above update operation disguised as an aggregate operation:
new_value = 15
db.mycollection.aggregate([
{ "$addFields": {
"value": { "$avg": ["$value", new_value] }
} },
{ "$out": "mycollection" }
])
or with MongoDB 3.2 using $project
as
new_value = 15
db.mycollection.aggregate([
{ "$project": {
"value": { "$avg": ["$value", new_value] }
} },
{ "$out": "mycollection" }
])
Upvotes: 2