Mongodb 聚合 - 首先创建项目列表并获取项目的交集
Mongodb aggregation - first create item list and get intersect of items
我有如下文件,
{
"_id" : ObjectId("5539d45ee3cd0e48e99c3fa6"),
"userId" : 1,
"movieId" : 6,
"rating" : 2.0000000000000000,
"timestamp" : 9.80731e+008
}
然后我需要为给定的两个用户(如 userId:1 和 userId:2)获取公共(相交)项目
例如,
{
"_id" : ObjectId("5539d45ee3cd0e48e99c1fa7"),
"userId" : 1,
"movieId" : 22,
"rating" : 3.0000000000000000,
"timestamp" : 9.80731e+008
},
{
"_id" : ObjectId("5539d45ee3cd0e48e99c1fa8"),
"userId" : 1,
"movieId" : 32,
"rating" : 2.0000000000000000,
"timestamp" : 9.80732e+008
},
{
"_id" : ObjectId("5539d45ee3cd0e48e99c1fa9"),
"userId" : 2,
"movieId" : 32,
"rating" : 4.0000000000000000,
"timestamp" : 9.80732e+008
},
{
"_id" : ObjectId("5539d45ee3cd0e48e99c1fa3"),
"userId" : 2,
"movieId" : 6,
"rating" : 5.0000000000000000,
"timestamp" : 9.80731e+008
}
然后我需要得到结果 [6,32]
我试过这样做,
aggregate([{"$match":{"$or":[{"userId":2},{"userId":1}]}},{"$group":{"_id":"$userId","movie":{"$addToSet":"$movieId"}}}])
但是不起作用。
我该怎么做?
试试这个:
db.movies.aggregate(
// Limit rating records to the relevant users
{$match:{userId:{$in:[1,2]}}},
// For each movie rated by either user, keep track of how many users rated the movie.
{$group:{_id:'$movieId',users:{$sum:1}}},
// Restrict the result to only movies rated by both users.
{$match:{users:2}}
)
使用 set operators 您可以获得预期的结果,过滤掉相同 user/movie 对可能重复的条目:
db.collection.aggregate([
{$match: {"$or":[{"userId":2},{"userId":1}]}},
{$group: {_id: "$movieId", users: {$addToSet: "$userId"}}},
{$project: { movieId: "$_id", _id: 0, allUsersIncluded: { $setIsSubset: [ [1,2], "$users"]}}},
{$match: { allUsersIncluded: true }},
{$group: { _id: null, movies: {$addToSet: "$movieId"}}}
])
正在制作,以你的例子为例:
{ "_id" : null, "movies" : [ 32, 6 ] }
- 第一个
$match
阶段将只保留用户 1 或 2 的文档;
- 第一个
$group
阶段将使用 $addToSet
为 每个 电影构建了解该电影的用户集;
- 此时,所有文档在
users
中都有 [1]
、[2]
、[1,2]
或 [2,1]
。使用 $setIsSubset
我在以下 $project
/$match
阶段过滤掉前两种情况;
- 最后,我只需要将一个电影集中的所有 movieId 分组。
我有如下文件,
{
"_id" : ObjectId("5539d45ee3cd0e48e99c3fa6"),
"userId" : 1,
"movieId" : 6,
"rating" : 2.0000000000000000,
"timestamp" : 9.80731e+008
}
然后我需要为给定的两个用户(如 userId:1 和 userId:2)获取公共(相交)项目
例如,
{
"_id" : ObjectId("5539d45ee3cd0e48e99c1fa7"),
"userId" : 1,
"movieId" : 22,
"rating" : 3.0000000000000000,
"timestamp" : 9.80731e+008
},
{
"_id" : ObjectId("5539d45ee3cd0e48e99c1fa8"),
"userId" : 1,
"movieId" : 32,
"rating" : 2.0000000000000000,
"timestamp" : 9.80732e+008
},
{
"_id" : ObjectId("5539d45ee3cd0e48e99c1fa9"),
"userId" : 2,
"movieId" : 32,
"rating" : 4.0000000000000000,
"timestamp" : 9.80732e+008
},
{
"_id" : ObjectId("5539d45ee3cd0e48e99c1fa3"),
"userId" : 2,
"movieId" : 6,
"rating" : 5.0000000000000000,
"timestamp" : 9.80731e+008
}
然后我需要得到结果 [6,32] 我试过这样做,
aggregate([{"$match":{"$or":[{"userId":2},{"userId":1}]}},{"$group":{"_id":"$userId","movie":{"$addToSet":"$movieId"}}}])
但是不起作用。
我该怎么做?
试试这个:
db.movies.aggregate(
// Limit rating records to the relevant users
{$match:{userId:{$in:[1,2]}}},
// For each movie rated by either user, keep track of how many users rated the movie.
{$group:{_id:'$movieId',users:{$sum:1}}},
// Restrict the result to only movies rated by both users.
{$match:{users:2}}
)
使用 set operators 您可以获得预期的结果,过滤掉相同 user/movie 对可能重复的条目:
db.collection.aggregate([
{$match: {"$or":[{"userId":2},{"userId":1}]}},
{$group: {_id: "$movieId", users: {$addToSet: "$userId"}}},
{$project: { movieId: "$_id", _id: 0, allUsersIncluded: { $setIsSubset: [ [1,2], "$users"]}}},
{$match: { allUsersIncluded: true }},
{$group: { _id: null, movies: {$addToSet: "$movieId"}}}
])
正在制作,以你的例子为例:
{ "_id" : null, "movies" : [ 32, 6 ] }
- 第一个
$match
阶段将只保留用户 1 或 2 的文档; - 第一个
$group
阶段将使用$addToSet
为 每个 电影构建了解该电影的用户集; - 此时,所有文档在
users
中都有[1]
、[2]
、[1,2]
或[2,1]
。使用$setIsSubset
我在以下$project
/$match
阶段过滤掉前两种情况; - 最后,我只需要将一个电影集中的所有 movieId 分组。