我有以下帖子文件:
{
"_id" : ObjectId("56960cd909b0d8801d145543"),
"title" : "Post title",
"body" : "Post body"
}
{
"_id" : ObjectId("56960cd909b0d8801d145544"),
"_post": ObjectId("56960cd909b0d8801d145543"),
"body" : "Comment one"
}
{
"_id" : ObjectId("56960cd909b0d8801d145544"),
"_post": ObjectId("56960cd909b0d8801d145543"),
"body" : "Comment Two"
}
从上面的文档中可以看出,这是我的帖子和评论实施的平面列表(如SO)。如果帖子有_post
字段,那么就是评论,但如果没有帖子本身。
当我查询问题56960cd909b0d8801d145543
时,我需要在以下视图中从mongoDB获得响应:
// query
Post.aggregate({_id: ObjectId("56960cd909b0d8801d145543")});
// result
{
"_id" : ObjectId("56960cd909b0d8801d145543"),
"title" : "Post title",
"body" : "Post body",
"comments" [{
"_id" : ObjectId("56960cd909b0d8801d145544"),
"_post": ObjectId("56960cd909b0d8801d145543"),
"body" : "Comment one"
},
{
"_id" : ObjectId("56960cd909b0d8801d145544"),
"_post": ObjectId("56960cd909b0d8801d145543"),
"body" : "Comment Two"
}]
}
如何构建聚合pipilenes以获得上面的结果?
答案 0 :(得分:1)
以下管道适用于您:
post_id
管道的结构使得您的第一步 $project
运算符阶段是将字段comments
投影为按键用作组在下一个管道阶段。由于您的架构是分层的,因此您需要此字段用于父/根文档。 $ifNull
运算符将充当coalesce运算符,如果文档中不存在该字段,则返回替换值。
下一个管道步骤, $group
管道阶段会尝试对数据进行分组以处理它们。 $group
管道运算符类似于SQL的GROUP BY子句。在SQL中,除非我们使用任何聚合函数,否则我们不能使用GROUP BY。同样,我们也必须在MongoDB中使用聚合函数。在这种情况下,您需要 $push
运算符来创建comments数组。然后使用 $first
运算符累积其他字段。
最后一步涉及使用comments数组,以便删除包含帖子详细信息的文档,这绝对不是注释类型。这可以通过 $setDifference
和 $map
运算符实现。 $map
运算符本质上创建了一个新的数组字段,该字段通过子表达式中的计算逻辑将数值保存到数组的每个元素。 $setDifference
运算符然后返回一个集合,其中的元素出现在第一个集合中但不出现在第二个集合中;即执行第二组相对于第一组的相对补码。在这种情况下,它将通过_id
属性返回包含与父文档无关的元素的最终INNER JOIN
数组。