如何在Mongo中进行聚合分组并显示其他字段?

3

我需要运行两次分组查询来找到评论中平均点赞最高的帖子。以下是我的查询的初始阶段。

db.posts.aggregate([
    {"$unwind": "$comments"},
    {"$match":
        {
            "$comments.type": {
                "$ne" : "spam"
            },
        }
    }
])

运行上述查询后,我看到的内容如下所示。
    {
        "_id" : ObjectId("50b59cd75bed76f46522c465"),
        "comment_id" : 49,
        "post_id" : 29,
        "likes" : {
            "type" : "accepted",
            "like" : 3
        }
    },
    {
        "_id" : ObjectId("50b59cd75bed76f46522c465"),
        "comment_id" : 49,
        "post_id" : 29,
        "likes" : {
            "type" : "rejected",
            "like" : 7
        }
    }

现在我想要做的是,首先找到这些有效记录中特定评论获得的平均点赞数,然后在每篇帖子中,将每条评论的平均点赞数相加,再除以每篇帖子总共的评论数,以此求得每个帖子的平均点赞数。
请注意,comment_id 仅在同一 post_id 中才是唯一的。换句话说,存在 post_id 为28,comment_id 为49 的记录。
我尝试了以下查询。
db.posts.aggregate([
    {"$unwind": "$comments"},
    {"$match":
        {
            "$comments.type": {
                "$ne" : "spam"
            },
        }
    },
    {"$group" :
        {
            "_id": "$_id",
            "comment_avg":
            {
                "$avg":"$comments.like"
            }
        }
    }])

我得到以下内容:
{
            "_id" : ObjectId("50b59cd75bed76f46522c44d"),
            "comment_avg" : 61.074253191058865
        },
        {
            "_id" : ObjectId("50b59cd75bed76f46522c34e"),
            "comment_avg" : 46.82622896256565
        }

如您所见,我已经丢失了post_id信息。我尝试使用$project,但我认为我做错了。


有些不对劲 - 在你给出的第一个样本输出中,“comments”文档在哪里?如果您展开$comments,每个结果输出文档中都必须有“comments”:{something}。您是否从第一次运行的聚合中省略了其他步骤?无论如何,您应该按post_id、comment_id而不是_id进行分组。 - Asya Kamsky
运行 unwind 后的第一个输出是: - Kim Stacks
这是不可能的,它缺少了注释字段。 - Asya Kamsky
1个回答

1
您还没有发布初始文档结构。
Document Structure:

{
    "_id" : ObjectId("50b59cd75bed76f46522c471"),
    "comment_id" : 61,
    "post_id" : 29,
    "comments" : [
                   {
                       "type" : "accepted",
                       "like" : 3
                   },
                   {
                      "type" : "rejected",
                      "like" : 3
                   },
                   {
                      "type" : "spam",
                      "like" : 3
                   }
                ]
}

假设您的文档结构如上所示,我已经编写了这个查询。您需要根据自己的需求进行操作。
db.posts.aggregate([
        {$unwind:"$comments"},
        {$match:{"$comments.type":{$ne:"spam"}}},
        {$group:{_id:{post_id:"$post_id",comment_id:"$comment_id"},LikeSum:{$sum:"$comments.like"}}},
        {$group:{_id:{post_id:"$_id.post_id"},AvgComments:{$avg:"$LikeSum"}}},
        {$sort:{AvgComments:-1}},
        {$limit:1}
              ])

以上查询的构造方式如下:
1.) Unwind the comments array and form individual documents for each element in the comments array
2.) Select only the non-spam comments
3.) Calculate the sum of likes for each comment of all posts
4.) Calculate the average Comment likes for each post
5.) Sort documents in descending order of Average Comment Likes
6.) Select only the first document.

输出的文档将类似于:
{
    "result" : [
        {
            "_id" : {
                       "post_id" : xx
                    },
            "AvgComments" : xx.xx // Avg Comment likes for post xx
        }
               ],
    "ok" : 1
}

谢谢。我刚看到你的回答。晚饭后我会试一下这个。 - Kim Stacks
@KimStacks 我已更新查询以列出具有最高平均评论点赞数的 post_id。 - Amarnath Krishnan
嘿,谢谢!你的查询有点起作用了。我得到的最高平均评论点赞数不是我预期的。但这可能是我加载数据库的方式导致的。既然逻辑是正确的,我会将你的答案标记为正确的。 - Kim Stacks

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接