Mongodb aggregation - first create item list and get intersect of items

大城市里の小女人 提交于 2020-01-06 19:27:11

问题


I have the Documents as follows,

{
    "_id" : ObjectId("5539d45ee3cd0e48e99c3fa6"),
    "userId" : 1,
    "movieId" : 6,
    "rating" : 2.0000000000000000,
    "timestamp" : 9.80731e+008
}

then I need to get the common(intersect) items for given two users (like userId:1 and userId:2)

for example,

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

then I need to get the result as [6,32] I tried to do this way ,

aggregate([{"$match":{"$or":[{"userId":2},{"userId":1}]}},{"$group":{"_id":"$userId","movie":{"$addToSet":"$movieId"}}}])

But doesn't work.

How can I do this?


回答1:


Try this:

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



回答2:


Using the set operators you can achieve the desired result, filtering out possible duplicate entries for the same user/movie pair:

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

Producing, given your example:

{ "_id" : null, "movies" : [ 32, 6 ] }
  • The first $match stage will keep only documents for users 1 or 2;
  • the first $group stage will use $addToSet to build for each movie the set of users knowing that movie;
  • at this point, all documents have in users either [1], [2], [1,2] or [2,1]. Using $setIsSubset I filter out the former two cases in the following $project/$match stages;
  • finally, I only have to group back all movieId in one movie set.


来源:https://stackoverflow.com/questions/31230449/mongodb-aggregation-first-create-item-list-and-get-intersect-of-items

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!