Reputation: 647
I'm trying to find my way around MongoDB. It's the first time I'm using this database, coming from MySQL. But for a chat application I'm making, MongoDB was recommended as a better fit.
I have two collections:
conversations in which I store the members userID (which is stored in a MySQL database) and the join date.
{
"_id" : ObjectId("5e35f2c840713a43aeeeb3d9"),
"members" : [
{
"uID" : "1",
"j" : 1580580922
},
{
"uID" : "4",
"j" : 1580580922
},
{
"uID" : "5",
"j" : 1580580922
}
]
}
messages in which I store the sender (userID), message, timestamp, conversationID (from the collection above), read and delivered status
{
"_id" : ObjectId("5e35ee5f40713a43aeeeb1c5"),
"c_ID" : ObjectId("5e35f2c840713a43aeeeb3d9"),
"fromID" : "1",
"msg" : "What's up?",
"t" : 1580591922,
"d" : {
"4" : 1580592039
},
"r" : {
"4" : 1580592339
}
}
What I want to do now is query the conversations for a specific user, let's say userID 1, together with the last message sent in that conversation.
I came up with the following:
db.getCollection('conversations').aggregate(
[{
$match: {
"members.uID": "1"
}
},
{
$lookup: {
as: 'lastMessage',
foreignField: 'c_ID',
from: 'messages',
localField: '_id',
}
},
])
But the problem here is that it lists all the messages, not only the last one. So I would like to limit this to 1, or if there is an alternative approach.. please let me know.
Any help is appreciated!
Upvotes: 1
Views: 51
Reputation: 17858
I guess we can understand the last message from timestamp field.
After $match
, and $lookup
stages, we need to $unwind messages, and then $sort by timestamp.
Now the first message in the messages array is the lastMessage, so when we group, we push the first message as lastMessage, and finally $replaceRoot to shape our result.
If so you can use the following aggregation:
db.conversations.aggregate([
{
$match: {
"members.uID": "1"
}
},
{
$lookup: {
foreignField: "c_ID",
from: "messages",
localField: "_id",
as: "messages"
}
},
{
"$unwind": "$messages"
},
{
"$sort": {
"messages.t": -1
}
},
{
"$group": {
"_id": "$_id",
"lastMessage": {
"$first": "$messages"
},
"allFields": {
"$first": "$$ROOT"
}
}
},
{
"$replaceRoot": {
"newRoot": {
"$mergeObjects": [
"$allFields",
{
"lastMessage": "$lastMessage"
}
]
}
}
},
{
$project: {
messages: 0
}
}
])
If the messages array is already sorted, the solution can be simplified, but this is a general solution.
Upvotes: 1