MongoDB 聚合框架不保留通过 $addFields 添加的内容

问题描述 投票:0回答:5

字段已添加但随后消失。 这是 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 }
mongodb aggregation-framework
5个回答
6
投票

聚合仅从您的集合中读取数据;它也不编辑集合。考虑聚合的最佳方法是读取一些数据并对其进行操作以供立即使用。

如果你想在主源中更改它,那么你必须使用 update 方法。

或者更简单的方法(不是最好但简单)

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

3
投票

Nozar 的答案正确的,但是 .save() 现已弃用。

不要使用他/她的确切答案,而是使用 .updateOne 和 $set 进行修改。

旧/已弃用的答案:

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

新/工作答案:

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

注意:在我的示例中,我使用“name”来过滤(在本例中基本上匹配)“users”集合中的文档,但您可以使用任何唯一字段(例如 _id 字段)。

感谢 Nozar 引导我找到了我提供的更新答案,因为我刚刚在我的项目中使用了它! (在我的项目中,我在 $addFields 管道阶段之前使用了 $match 管道阶段,因为我只是想对我的集合中的单个文档而不是所有文档执行此操作)


1
投票

聚合管道不会改变原始数据;它的作用是获取数据的临时内存副本并对其执行一系列操作(仍在内存中)并将其发送到客户端。

这与您可以做的方式类似

db.collection.find().sort()
;那里的排序只会改变返回给客户端的内容,不会改变数据库中存储的内容。

唯一的例外是当您使用$out阶段时,它将聚合结果保存到另一个集合中。您可以看到,因为他们必须添加特殊类型的阶段来执行此操作,所以正常的聚合不会写回存储的数据。


0
投票

原因是,您的两种方法完全不同。在聚合中,您在该查询中使用$addFields,您将获得totalAge。但是根据您的查找查询,您可以获得存储在数据库中的特定数据。这里您没有计算totalAge

希望你能理解。


0
投票

似乎你可以使用$merge,例如:

> db.users.aggregate([{$addFields:{totalAge:{$sum:"$age"}}},{merge: "users"}])
© www.soinside.com 2019 - 2024. All rights reserved.