Mongodb聚合 - 首先创建项目列表并获得项目的交叉

时间:2015-07-05 12:44:24

标签: mongodb aggregation-framework

我的文件如下,

{
    "_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"}}}])

但是没有用。

我该怎么做?

2 个答案:

答案 0 :(得分:0)

试试这个:

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}}
)

答案 1 :(得分:0)

使用set operators可以获得所需的结果,过滤掉相同用户/电影对的可能重复条目:

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分组。