Reputation: 1952
i have total 3 collections: 1. users 2. posts 3. actions
My collections look like these:
users:
{
"_id" : ObjectId("57ee65fef5a0c032877725db"),
"fbId" : "EAAXZA4sZCZBKmgBAKe0JpJPrp7utWME6xbHT9yFD",
"name" : "Aftab",
"email" : "[email protected]",
"gender" : "male",
"__v" : NumberInt(0),
"updatedAt" : ISODate("2016-10-10T05:11:35.344+0000"),
"score" : NumberInt(90)
}
actions:
{
"_id" : ObjectId("57f7a0ba3a603627658afdd3"),
"updatedAt" : ISODate("2016-10-07T13:18:50.815+0000"),
"createdAt" : ISODate("2016-10-07T13:18:50.815+0000"),
"userId" : ObjectId("57ee65fef5a0c032877725db"),
"postId" : ObjectId("57f4b5e98899081203883a1b"),
"type" : "like"
}
{
"_id" : ObjectId("57f7a0ba3a603627658afdd4"),
"updatedAt" : ISODate("2016-10-07T13:18:50.815+0000"),
"createdAt" : ISODate("2016-10-07T13:18:50.815+0000"),
"userId" : ObjectId("57ee65fef5a0c032877725db"),
"postId" : ObjectId("57f4b5d58899081203883a1a"),
"type" : "dismiss"
}
posts:
{
"_id" : ObjectId("57f24593e272b5199e9351b9"),
"imgFileLocation" : "http://xxxx/buybye-platform/uploads/image-1475495315229",
"description" : "cool cool",
"title" : "Bad Image ",
"userId" : ObjectId("57f21e3d0b787d0f7ad76dd0"),
"__v" : NumberInt(0)
}
{
"_id" : ObjectId("57f4b5d58899081203883a1a"),
"imgFileLocation" : "http://xxx/buybye-platform/uploads/image-1475655125125",
"description" : "cool & cool",
"title" : "Good Image",
"userId" : ObjectId("57f21e3d0b787d0f7ad76dd0"),
"__v" : NumberInt(0)
}
user can create posts, and other users can perform actions on those posts
posts collection has a reference of userId and actions collection has ref of userId(who performed that action), postId(on which post) and action-type(like/dislike/dismiss)
I need to query to get all actions performed on a specific user posts
I have able to get all posts against a user, which is pretty straight-forward and is an array. now I need to get all actions performed on every single post of this posts array.
Upvotes: 1
Views: 1573
Reputation: 5908
If you want a solution that leverages the aggregation framework, you can use the $lookup
stage that was introduced starting with MongoDB v3.2.
For example, if you want to return a result set containing the details of a post and an array of all the actions performed on that particular post, you can run the following aggregation query:
/*
* QUERY #1
*/
db.posts.aggregate([
{
$lookup: {
from: 'actions',
localField: '_id',
foreignField: 'postId',
as: 'post_actions'
}
}
]);
/*
* RESULT SET #1
*/
{
"_id" : ObjectId("57ff4512a134e614a7178c1d"),
"imgFileLocation" : "http://xxxx/buybye-platform/uploads/image-1475495315229",
"description" : "cool cool",
"title" : "Bad Image ",
"userId" : ObjectId("57f21e3d0b787d0f7ad76dd0"),
"__v" : 0,
"post_actions" : [
{
"_id" : ObjectId("57ff4563a134e614a7178c1e"),
"updatedAt" : ISODate("2016-10-07T13:18:50.815Z"),
"createdAt" : ISODate("2016-10-07T13:18:50.815Z"),
"userId" : ObjectId("57ee65fef5a0c032877725db"),
"postId" : ObjectId("57ff4512a134e614a7178c1d"),
"type" : "like"
},
{
"_id" : ObjectId("57ff4564a134e614a7178c1f"),
"updatedAt" : ISODate("2016-10-07T13:18:50.815Z"),
"createdAt" : ISODate("2016-10-07T13:18:50.815Z"),
"userId" : ObjectId("57ee65fef5a0c032877725db"),
"postId" : ObjectId("57ff4512a134e614a7178c1d"),
"type" : "share"
}
]
}
Otherwise, if you want to only retrieve the actions for a specific array of posts, you can add a $match
stage in the aggregation pipeline:
const postIdsArray = [
ObjectId("57ff4512a134e614a7178c1d"),
ObjectId("57ee65fef5a0c032877725db")
];
/*
* QUERY #2
*/
db.posts.aggregate([
{
$match: {
_id: {
$in: postIdsArray
}
}
},
{
$lookup: {
from: 'actions',
localField: '_id',
foreignField: 'postId',
as: 'post_actions'
}
}
]);
Furthermore, if you would want to only retrieve the total count of actions performed on a post, you can add an $unwind
stage and then $group
all the results:
/*
* QUERY #3
*/
db.posts.aggregate([
{
$lookup: {
from: 'actions',
localField: '_id',
foreignField: 'postId',
as: 'post_actions'
}
},
{
$unwind: '$post_actions'
},
{
$group: {
_id: '$_id',
posts: { $sum: 1 }
}
}
]);
/*
* RESULT SET #3
*/
{ "_id" : ObjectId("57ff4512a134e614a7178c1d"), "posts" : 2 }
UPDATE #1
If you want to retrieve only the actions that are of a certain type (e.g.: like, share etc.), you can add an additional $match
stage in your aggregation pipeline, after you $unwind
the post_actions array retrieved in the $lookup
stage.
For example, the first query would become:
/*
* UPDATED QUERY #1
*/
db.posts.aggregate([
{
$lookup: {
from: 'actions',
localField: '_id',
foreignField: 'postId',
as: 'post_actions'
}
},
{
$unwind: '$post_actions'
},
{
$match: {
"post_actions.type": 'like'
}
}
]);
The second query would become:
const postIdsArray = [
ObjectId("57ff4512a134e614a7178c1d"),
ObjectId("57ee65fef5a0c032877725db")
];
/*
* UPDATED QUERY #2
*/
db.posts.aggregate([
{
$match: {
_id: {
$in: postIdsArray
}
}
},
{
$lookup: {
from: 'actions',
localField: '_id',
foreignField: 'postId',
as: 'post_actions'
}
},
{
$unwind: '$post_actions'
},
{
$match: {
"post_actions.type": 'like'
}
}
]);
The third query would become:
/*
* UPDATED QUERY #3
*/
db.posts.aggregate([
{
$lookup: {
from: 'actions',
localField: '_id',
foreignField: 'postId',
as: 'post_actions'
}
},
{
$unwind: '$post_actions'
},
{
$match: {
"post_actions.type": 'like'
}
},
{
$group: {
_id: '$_id',
posts: { $sum: 1 }
}
}
]);
Upvotes: 3