MongoDB aggregate framework not keeping what was added with $addFields
Asked Answered
U

5

2

Field is added but then disappears. Here is the code from within the mongo shell:

> db.users.aggregate([{$addFields:{totalAge:{$sum:"$age"}}}])
{ "_id" : ObjectId("5acb81b53306361018814849"), "name" : "A", "age" : 1, "totalAge" : 1 }
{ "_id" : ObjectId("5acb81b5330636101881484a"), "name" : "B", "age" : 2, "totalAge" : 2 }
{ "_id" : ObjectId("5acb81b5330636101881484b"), "name" : "C", "age" : 3, "totalAge" : 3 }
> db.users.find().pretty()
{ "_id" : ObjectId("5acb81b53306361018814849"), "name" : "A", "age" : 1 }
{ "_id" : ObjectId("5acb81b5330636101881484a"), "name" : "B", "age" : 2 }
{ "_id" : ObjectId("5acb81b5330636101881484b"), "name" : "C", "age" : 3 }
Uppermost answered 9/4, 2018 at 23:7 Comment(2)
Please add some more detail. Check here on how to ask good questions: stackoverflow.com/help/how-to-askAllen
As of MongoDB v3.6 (current) Aggregation Pipeline does not alter documents. You may find $out stage useful.Carotid
P
6

Aggregation only reads data from your collection; it does not edit the collection too. The best way to think about aggregation is that you read some data and manipulate it for your immediate usage.

If you want change it in main source then you must use the update method.

Or an easier way (Not best but easy)

db.users.aggregate([{$addFields:{totalAge:{$sum:"$age"}}}]).forEach(function (x){
    db.users.save(x)
})
Palmapalmaceous answered 10/4, 2018 at 5:32 Comment(0)
B
3

Nozar's answer was correct, but .save() is now deprecated.

Instead of using his/her exact answer, modify it by using .updateOne and $set.

Old/deprecated answer:

db.users
    .aggregate([{$addFields:{totalAge:{$sum:"$age"}}}])
    .forEach(function (x){db.users.save(x)})

New/working answer:

db.users
    .aggregate([{$addFields:{totalAge:{$sum:"$age"}}}])
    .forEach(function (x){db.users.updateOne({name: x.name}, {$set: {totalAge: x.totalAge}})})

Note: In my example, I'm using 'name' to filter (essentially match, in this case) the documents in 'users' collection, but you can use any unique field (e.g. _id field).

Shoutout to Nozar for leading me to the updated answer I provided, as I just used it in my project! (In my project, I used a $match pipeline stage prior to the $addFields pipeline stage, as I was just looking to do this to a single document in my collection, rather than all documents)

Bolivar answered 3/10, 2021 at 22:24 Comment(0)
J
1

The aggregation pipeline doesn't alter the original data; what it does is to take a temporary in-memory copy of the data and perform a sequence of manipulations on it (still in-memory) and send it to the client.

It's similar to the way you can do db.collection.find().sort() ; the sorting there only changes what is being returned to the client, it doesn't change what is stored in the database.

The only exception is when you use the $out stage, which saves the result of the aggregation to another collection. You can see that, because they had to add a special type of stage to do this, that a normal aggregation does not write back to the stored data.

Jest answered 10/4, 2018 at 10:12 Comment(0)
P
0

The reason is that, your both approach totally different.In aggregation, you have use $addFields in that query you will get a totalAge. But according to your find query, you can get specific data which you have stored in a database.Here you did not calculate totalAge.

I hope you can understand it.

Planetesimal answered 10/4, 2018 at 4:30 Comment(0)
Z
0

Seems like you can use $merge, like:

> db.users.aggregate([{$addFields:{totalAge:{$sum:"$age"}}},{merge: "users"}])
Zennas answered 23/10, 2023 at 21:58 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.