mongodb - 如何使用 MongoDB 聚合框架对嵌套帖子进行分组?

标签 mongodb mongoose aggregation-framework

我有以下邮寄文件:

{
   "_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时,我需要在以下 View 中从 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"
   }]
}

我应该如何构建聚合管道以获得上面的结果?

最佳答案

以下管道应该适合您:

var pipeline = [
    {
        "$project": {
            "title": 1, "body": 1, 
            "post_id": { "$ifNull": [ "$_post", "$_id" ] }
        }
    },  
    {
        "$group": {
            "_id": "$post_id",
            "title": { "$first": "$title" },
            "body": { "$first": "$body" },
            "comments": {
                "$push": {
                    "_id": "$_id",
                    "_post": "$post_id",
                    "body": "$body"
                }
            }
        }
    },
    {
        "$project": {
            "title": 1, "body": 1,
            "comments": {
                "$setDifference": [
                    {
                        "$map": {
                            "input": "$comments",
                            "as": "el",
                            "in": {
                                "$cond": [
                                    { "$ne": [ "$$el._id", "$$el._post" ] },
                                    "$$el",
                                    false
                                ]
                            }
                        }
                    },
                    [false]
                ]
            }
        }
    }
];

Post.aggregate(pipeline, function (err, result) {
    if (err) { /* handle error */ };
    console.log(result);
});

管道的结构方式使得您的第一步, $project 算子阶段,就是投影领域post_id在下一个管道阶段用作按键分组。由于您的架构是分层的,因此您需要此字段作为父/根文档。 $ifNull 运算符将充当合并运算符,如果文档中不存在该字段,则返回替换值。

下一个管道步骤, $group 管道阶段尝试对数据进行分组来处理它们。 $group 管道运算符类似于 SQL 的 GROUP BY 子句。在 SQL 中,除非使用任何聚合函数,否则我们不能使用 GROUP BY。同样,我们也必须在 MongoDB 中使用聚合函数。在这种情况下,您需要 $push 运算符来创建评论数组。然后使用 $first 累积其他字段。 运算符。

最后一步涉及调整评论数组,以便删除包含帖子详细信息的文档,这绝对不是评论类型。这是通过 $setDifference 实现的。 $map 运营商。 $map 运算符本质上创建一个新的数组字段,该字段保存数组每个元素的子表达式中计算逻辑的结果值。 $setDifference 运算符然后返回一个集合,其中包含出现在第一个集合中但未出现在第二个集合中的元素;即执行第二组相对于第一组的相对补充。在这种情况下,它将返回最终的 comments包含与父文档不相关的元素的数组 _id属性。

关于mongodb - 如何使用 MongoDB 聚合框架对嵌套帖子进行分组?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34762343/

相关文章:

node.js - Wire 版本不支持 mongodb 中的 nodejs

ruby - 不运行 mongodb 的 mongoid 单元测试

mongodb - Docker +主管:如何初始化服务(mongo&elasticmq)?

node.js - 如何在 Express 中使用比较运算符过滤查询字符串

javascript - Mongoose MongoDB : LIKE operator in search

node.js - Mongoose 中 document.save() 后的人口数量错误

node.js - 表单 save mongoose 上随机生成 id

MongoDB $lookup 返回空数组

node.js - 选择当月生日的所有用户

MongoDB 在事先不知道所有字段的情况下聚合字段