user2672224
user2672224

Reputation: 27

MongoDB aggregate framework not keeping what was added with $addFields

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 }

Upvotes: 2

Views: 3013

Answers (5)

user109764
user109764

Reputation: 654

Seems like you can use $merge, like:

> db.users.aggregate([{$addFields:{totalAge:{$sum:"$age"}}},{merge: "users"}])

Upvotes: 0

amota
amota

Reputation: 331

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)

Upvotes: 3

Vince Bowdren
Vince Bowdren

Reputation: 9208

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.

Upvotes: 1

Nozar Safari
Nozar Safari

Reputation: 505

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)
})

Upvotes: 6

Naimish Kher
Naimish Kher

Reputation: 294

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.

Upvotes: 0

Related Questions