Reputation: 64276
I have messages system in mongodb. Messages object looks like this:
{
who: String,
whom: String,
when: Date
}
So, for example, when user 1 sends message to user 2 I have:
{ who: "1", whom: "2", when: MSG_DATE }
And when user 2 sends message to 1 in response the following row is added:
{ who: "2", whom: "1", when: MSG_DATE }
Now I need to collect unique dialogs in UI for user 1, for example.
[
{
"$match": {
"$or": [
{ "who": "1" },
{ "whom": "1" }
]
}
},
{
"$group": {
"_id": "a",
"dialogs_who": { "$addToSet": "$who" },
"dialogs_whom": { "$addToSet": "$whom" }
}
},
{
"$project": {
"name": "$_id",
"profiles": {
"$setUnion": [ "$dialogs_who", "$dialogs_whom" ]
}
}
}
]
This will return me : ["1", "2"]
. In code I just skip dialog 1
for user 1.
With this aggregation I search for messages where who
or whom
is user we are loading info for (1). Results are added to set to make it unique and finally two sets are merged into one. It works, bu I need to store latest date message for each dialog.
So if there are such rows in db:
{ who: "1", whom: "2", when: MSG_DATE1 },
{ who: "2", whom: "1", when: MSG_DATE2 },
{ who: "3", whom: "1", when: MSG_DATE3 },
{ who: "3", whom: "4", when: MSG_DATE4 } // It's not dialog with 1
Here we have two unique dialogs (minus dialog with 1) for user 1: ["1", "2", "3"]. How to add into aggregation storing of latest when
date for dialog with.
So if MSG_DATE2 > MSG_DATE_1 I want result like:
[
"2": MSG_DATE2,
"3": MSG_DATE4
}
Upvotes: 0
Views: 73
Reputation: 6629
This is the most appropriate answer I can think of. It may be long, but the logic is correct.
Test date:
/* 1 */
{
"_id" : ObjectId("612630679bd62cd759b1df00"),
"who" : "1",
"whom" : "2",
"when" : "20120820"
}
/* 2 */
{
"_id" : ObjectId("612630679bd62cd759b1df03"),
"who" : "2",
"whom" : "1",
"when" : "20120822"
}
/* 3 */
{
"_id" : ObjectId("612630679bd62cd759b1df06"),
"who" : "3",
"whom" : "1",
"when" : "20120825"
}
/* 4 */
{
"_id" : ObjectId("612630679bd62cd759b1df09"),
"who" : "3",
"whom" : "4",
"when" : "20120828"
}
Aggregate:
db.collection.aggregate([
{
$match:{"$or":[ { "who":"1"}, {"whom":"1"} ]}
},
{
$project:{
who:{
$first: {
$filter: {
input: [ "$who", "$whom" ],
as: "i",
cond: { $ne: [ "$$i", "1" ] }
}
}
},
when:1
}
},
{
$sort:{"when":-1}
},
{
$group:{_id:"$who", when:{"$first":"$when"}}
}
])
Result:
/* 1 */
{
"_id" : "2",
"when" : "20120822"
}
/* 2 */
{
"_id" : "3",
"when" : "20120825"
}
Upvotes: 1