Mongodb 聚合/项目子文档作为mongo中的顶级文档
在我的一个集合中执行了几个聚合步骤(管道步骤)之后,我将得到以下结果:Mongodb 聚合/项目子文档作为mongo中的顶级文档,mongodb,mongodb-query,Mongodb,Mongodb Query,在我的一个集合中执行了几个聚合步骤(管道步骤)之后,我将得到以下结果: { "_id" : ObjectId("574e7722bffe901713d383bb"), "eventname" : "Ball Passed", "command" : { "_id" : ObjectId("57ec6b6f6c61e919b578fe7c"), "name" : "Run", "strike" : 15, "s
{
"_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
}
这很好
但是,在聚合的下一步中,我希望得到以下结果:
{
"_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
?正如您所猜测的,$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
的产品仅允许您排除\u id。这意味着您需要手动列出要包括的所有字段。注意:从MongoDB的3.4版开始,可以排除
$project
阶段()
find
但是,您可以列出要隐藏的字段
可供替代的
(1)您可以使用以下方法将聚合结果重定向到另一个集合:
(2)即使结构不完全符合您的要求,您也可以执行查找
查询和隐藏字段:
db.commands.find({}, {_id:0, "command.score":0, eventname:0}).pretty()
它返回的结果与您要查找的内容非常接近:
{
"command" : {
"_id" : ObjectId("57ec6b6f6c61e919b578fe7c"),
"name" : "Run",
"strike" : 15,
"duration" : 123
}
}
如果子文档中有很多字段,并且偶尔会使用新字段更新,则投影不是一个可行的选项。幸运的是,从3.4开始,MongoDB有了一个名为的新操作符 您所要做的就是在管道的末尾添加一个新阶段
db.getCollection('sample').aggregate([
{
$replaceRoot: {newRoot: "$command"}
},
{
$project: {score: 0 } //exclude score field
}
])
这将为您提供所需的输出
注意,在聚合的情况下(特别是在阶段之后),“命令”文档可以是一个数组,并且可以包含多个文档。在这种情况下,您首先需要数组才能使用启动
Mongo 4.2
,聚合操作符可用于将一个文档替换为另一个文档(在本例中为子文档),作为$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
中也引入了聚合运算符,作为$project
仅用于删除字段时的另一种语法。我已经简化了文档。实际上,我在command
子文档中有70多个字段。我是否应该像上面那样对每个字段进行投影?是否有其他方法可以投影所有字段,但只跳过一个字段?我相信聚合只能让您隐藏_id。否则,逻辑只能在“要显示的字段列表”中工作。您还可以使用$out重定向结果,然后使用find(),其工作方式与此相反:它允许您列出要隐藏的字段..我使用建议更新了答案(“注释后更新”部分),因为MongoDB 3.4$project
可以排除字段: