If I have a user
and post
collection
{"_id": 1, "name": "User 1"}
{"_id": 2, "name": "User 2"}
{"_id": 1, "title": "Post 1", "userId": 1, "createdAt": ISODate("2017-07-24T04:12:54.255Z")}
{"_id": 2, "title": "Post 2", "userId": 1, "createdAt": ISODate("2017-07-25T04:12:54.255Z")}
{"_id": 3, "title": "Post 1", "userId": 2, "createdAt": ISODate("2017-07-24T04:12:54.255Z")}
How can I list all users with their latest post? Would be something like
{
"_id": 1,
"name": "User 1",
"post": {
"_id": 2,
"title": "Post 2",
"userId": 1,
"createdAt": ISODate("2017-07-25T04:12:54.255Z")
}
}
I know I can easily use $lookup, $unwind post, then $sort by post.createdAt, but that leave me with redundant user (User 1 will be listed twice for Post 1 and Post 2).
I don't know how can I use $group to remove duplicates while keep maintaining other fields (name, post.title, etc)
To sort documents in MongoDB, you need to use sort() method. The method accepts a document containing a list of fields along with their sorting order. To specify sorting order 1 and -1 are used. 1 is used for ascending order while -1 is used for descending order.
Starting in MongoDB 5.0, the $eq , $lt , $lte , $gt , and $gte comparison operators placed in an $expr operator can use an index on the from collection referenced in a $lookup stage. Limitations: Multikey indexes are not used.
We can use the following code to sort the documents in the teams collection first by “points” ascending and then by “rebounds” ascending: What is this? Notice that the documents are sorted by the “points” field ascending (smallest to largest) and then by the “rebounds” field ascending (smallest to largest).
I solved the duplicates using $group and $first
db.getCollection('user').aggregate([
{$lookup: {from: "post", localField: "_id", foreignField: "userId", as: "post"}},
{$unwind: { path: "$post", preserveNullAndEmptyArrays: true }},
{$sort: {"post.createdAt": -1}},
{$group: {"_id": "$_id", "name": {$first: "$name"}, "post": {$first: "$post"}},
{$project: {"_id": 1, "name": 1, "post": 1}}
])
Feel free to post your answer
You can solve this in a single aggregation step with the new $lookup syntax
db.getCollection('users').aggregate([{
'$lookup': {
'from': 'posts',
'let': {
'userId': '$_id'
},
'pipeline': [{
'$match': { '$expr': { '$eq': ['$userId', '$$userId'] } }
}, {
'$sort': { 'createdAt': -1 }
}, {
'$limit': 10
},
],
'as': 'posts'
}
}
])
Note: untested code, but the principle should be clear.
here is a way you can use
db.getCollection('post').aggregate([
{ $limit: 10 },
{$sort: {"createdAt": -1}},
{$lookup: {from: "user", localField: "userId", foreignField: "_id", as: "user"}},
])
you should query post which sorted by date and join with user. so if you want to provide a limit for posts then you can.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With