首页 > 解决方案 > 编写需要使用分组的 MongoDB 聚合查询时遇到问题

问题描述

我有一个集合,它存储用户活动数据,这些数据与用户是否对选定的关键字列表投赞成票或反对票有关,因为它们与标题目录相关。我需要在 Mongo 中执行一个聚合查询,它为我提供与所有用户的标题相关的每个关键字的累积分数 - 赞成票由 vote: true 和 downvote by vote: false 表示

使用 unwind 运算符作为我的第一步,然后是 group by,但这是我迷失的地方,因为我不确定是否按 titleId、keyword 和 vote 的组合进行分组;只是titleId 和关键字或只是titleId。以下是集合中数据的示例 -

期望在聚合查询的末尾看到一个按 titleId 分组的文档,其中包含一组对象,其中每个对象包含一个关键字和该关键字在该标题的上下文中的累积投票总数。

{ 
    "_id" : ObjectId("5d2eb0b20e91d1941540e2b5"), 
    "titleId" : "111222", 
    "userId" : "993f1e69-c6b0-44eb-a8a6-5db5dc42d425", 
    "activity" : [
        {
            "keyword" : "Road Trip", 
            "vote" : true
        }, 
        {
            "keyword" : "Friendship", 
            "vote" : true
        },
        {
            "keyword" : "Family Movie", 
            "vote" : true
        }
    ]
}
// ----------------------------------------------
{ 
    "_id" : ObjectId("5d38fd270e91d1941559bee0"), 
    "titleId" : "111222", 
    "userId" : "f92c7118-8930-4d30-8e07-8363737a6866", 
    "activity" : [
        {
            "keyword" : "Road Trip", 
            "vote" : false
        }, 
        {
            "keyword" : "Adventure", 
            "vote" : true
        }, 
        {
            "keyword" : "Family Movie", 
            "vote" : true
        }
    ]
}
// ----------------------------------------------
{ 
    "_id" : ObjectId("5d38fd270e91d1941559bee0"), 
    "titleId" : "111222", 
    "userId" : "f92c7118-8930-4d30-8e07-8363737a6866", 
    "activity" : [
        {
            "keyword" : "Road Trip", 
            "vote" : false
        }, 
        {
            "keyword" : "Adventure", 
            "vote" : false
        }, 
        {
            "keyword" : "Family Movie", 
            "vote" : false
        }
    ]
}
// ----------------------------------------------
{ 
    "_id" : ObjectId("5d2eb0b20e91d1941540e2b5"), 
    "titleId" : "444222", 
    "userId" : "993f1e69-c6b0-44eb-a8a6-5db5dc42d425", 
    "activity" : [
        {
            "keyword" : "Educational film and videos", 
            "vote" : true
        }, 
        {
            "keyword" : "Space", 
            "vote" : true
        }
    ]
}
// ----------------------------------------------
{ 
    "_id" : ObjectId("5d38fd270e91d1941559bee0"), 
    "titleId" : "444222", 
    "userId" : "f92c7118-8930-4d80-8e07-8363737a6866", 
    "activity" : [
        {
            "keyword" : "Action", 
            "vote" : false
        }, 
        {
            "keyword" : "Adventure", 
            "vote" : false
        }, 
        {
            "keyword" : "Sci Fi", 
            "vote" : true
        }
    ]
}

期望看到一个按 titleId 分组的文档和一组对象,其中每个对象包含一个关键字以及该关键字在该标题的上下文中的累积投票总数。

标签: mongodbaggregation-framework

解决方案


以下查询可以为我们提供预期的输出:

db.collection.aggregate([
    {
        $unwind:"$activity"
    },
    {
        $group:{
            "_id":{
                "titleId":"$titleId",
                "keyword":"$activity.keyword"
            },
            "votes":{
                $sum:{
                    $cond:[
                        {
                            $eq:["$activity.vote",true]
                        },
                        1,
                        -1
                    ]
                }
            }
        }
    },
    {
        $group:{
            "_id":"$_id.titleId",
            "titleId":{
                $first:"$_id.titleId"
            },
            "activity":{
                $push:{
                    "keyword":"$_id.keyword",
                    "votes":"$votes"
                }
            }
        }
    },
    {
        $project:{
            "_id":0
        }
    }
]).pretty()

输出:

{
    "titleId" : "111222",
    "activity" : [
        {
            "keyword" : "Road Trip",
            "votes" : -1
        },
        {
            "keyword" : "Adventure",
            "votes" : 0
        },
        {
            "keyword" : "Friendship",
            "votes" : 1
        },
        {
            "keyword" : "Family Movie",
            "votes" : 1
        }
    ]
}
{
    "titleId" : "444222",
    "activity" : [
        {
            "keyword" : "Adventure",
            "votes" : -1
        },
        {
            "keyword" : "Sci Fi",
            "votes" : 1
        },
        {
            "keyword" : "Action",
            "votes" : -1
        },
        {
            "keyword" : "Educational film and videos",
            "votes" : 1
        },
        {
            "keyword" : "Space",
            "votes" : 1
        }
    ]
}

聚合阶段:

  • 第一阶段:展开“活动”数组。现在数组的每个元素都有一个文档
  • 第二阶段:根据标题ID和活动关键字进行分组并计算票数。1 表示赞成,-1 表示反对。
  • 第三阶段:仅根据标题 ID 进行分组,并将所有活动合并到一个数组中
  • 第四阶段:从输出中消除不必要的字段

推荐阅读