问题
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