在我的一个集合中经过几个聚合步骤(管道步骤)之后,我最终得到以下结果:
{
"_id" : ObjectId("574e7722bffe901713d383bb"),
"eventname" : "Ball Passed",
"command" : {
"_id" : ObjectId("57ec6b6f6c61e919b578fe7c"),
"name" : "Run",
"strike" : 15,
"score" : true,
"duration" : 123
}
}
{
"_id" : ObjectId("57ec6b6f6c61e919b578ff8a"),
"eventname" : "Ball Passed",
"command" : {
"_id" : ObjectId("573d688d080cc2cbe8aecbbc"),
"name" : "Run",
"strike" : 12,
"score" : false,
"duration" : 597
}
}
哪个好!
但是,在汇总的下一步中,我希望得到以下结果:
{
"_id" : ObjectId("57ec6b6f6c61e919b578fe7c"),
"name" : "Run",
"strike" : 15,
"duration" : 123
}
{
"_id" : ObjectId("573d688d080cc2cbe8aecbbc"),
"name" : "Run",
"strike" : 12,
"duration" : 597
}
如果您有通知,则command
字段应成为顶级文档,并且应跳过command.score
。
如何一步实现这一目标?如果只能在一个步骤中完成,那么可以分多步进行?我想我可以使用$project
?
答案 0 :(得分:13)
如果子文档中有很多很多字段,有时会使用新字段进行更新,那么投影就不是一个可行的选择。幸运的是,从3.4开始,MongoDB有一个名为 $replaceRoot 的新运算符。
您所要做的就是在管道末尾添加一个新阶段。
db.getCollection('sample').aggregate([
{
$replaceRoot: {newRoot: "$command"}
},
{
$project: {score: 0 } //exclude score field
}
])
这将为您提供所需的输出。
请注意,在聚合的情况下(特别是在 $group 阶段之后),'command'文档可能是一个数组,可能包含多个文档。在这种情况下,您需要首先 $unwind 数组才能使用 $replaceRoot 。
答案 1 :(得分:8)
正如您所猜测的那样,$project
允许您这样做:
db.col.aggregate([
{
$project :
{
_id: "$command._id",
name: "$command.name",
strike: "$command.strike",
duration: "$command.duration"
}
}
]).pretty()
我插入了您之前的结果,上面的查询返回了这个:
{
"_id" : ObjectId("57ec6b6f6c61e919b578fe7c"),
"name" : "Run",
"strike" : 15,
"duration" : 123
}
{
"_id" : ObjectId("573d688d080cc2cbe8aecbbc"),
"name" : "Run",
"strike" : 12,
"duration" : 597
}
所以使用此$product
管道您的查询应该会产生您要查找的结果。
如果确切的结构不是您主要关注的问题,而是排除少数字段(无需列出要包含的所有字段),那么您可以使用find()
代替aggregate()
。
aggregate
的产品只允许您排除_id。这意味着您需要手动列出要包含的所有字段。
注意:从MongoDB版本3.4开始,可以排除$project
阶段(https://docs.mongodb.com/manual/reference/operator/aggregation/project/#exclude-fields)
find
但是,您可以列出要隐藏的字段。
(1)您可以使用$out将汇总结果重定向到另一个集合:
{ $out : "commands" }
(2)即使结构不符合您的要求,您也可以进行find
查询,隐藏字段:
db.commands.find({}, {_id:0, "command.score":0, eventname:0}).pretty()
它会返回这个,这与你想要的非常接近:
{
"command" : {
"_id" : ObjectId("57ec6b6f6c61e919b578fe7c"),
"name" : "Run",
"strike" : 15,
"duration" : 123
}
}
答案 2 :(得分:0)
从Mongo 4.2
开始,$replaceWith
聚合运算符可用于将另一个文档(在本例中为子文档)替换为$replaceRoot
的语法糖。
// { "eventname": "Ball Passed", "command": { "_id": "57e...", "name": "Run", "strike": 15, "score": true, "duration": 123 } }
// { "eventname": "Ball Passed", "command": { "_id": "573...", "name": "Run", "strike": 12, "score": false, "duration": 597 } }
db.collection.aggregate([
{ $replaceWith: "$command" }, // replaces the document by the content of "command"
{ $unset: ["score"] } // drops the "score" field
])
// { "_id" : "57e...", "name" : "Run", "strike" : 15, "duration" : 123 }
// { "_id" : "573...", "name" : "Run", "strike" : 12, "duration" : 597 }
还请注意,Mongo 4.2
中还引入了$unset
聚合运算符,作为$project
的替代语法(仅用于删除字段时使用)。