如何使用 MongoDB 聚合框架查找组中的最新项目?

How to find the most recent item in a group using MongoDB aggregation framework?

我有一个 collection 存储消息的地方,它看起来像这样:

id sender receiver date
------------------------
1     1       2    30-May-15 3:14:48 PM
2     2       1    30-May-15 3:16:28 PM
3     1       3    30-May-15 3:20:00 PM
4     1       2    30-May-15 3:21:48 PM
5     3       2    30-May-15 3:25:15 PM
6     4       1    30-May-15 3:30:05 PM

发件人包含发送消息的人的 ID,接收者包含将接收消息的人的 ID。

我想创建一个最近的联系人列表。也就是说,找到某个人(作为发送者或接收者)说过话的所有人,按日期降序排列。如果重复,我只需要保留最近的联系方式。

例如:如果我搜索与id=1的人交谈的人我想获得以下人的id:4、2、3(与他交谈过的人):4是最新的人(日期 2015 年 5 月 30 日 3:30:05 下午),2 人在 4 点之前(日期 2015 年 5 月 30 日 3:21:48 下午),3 人在 2 点之前(日期 2015 年 5 月 30 日 3:20:00下午)。

我试过这个查询:

messages.aggregate({$match: {$or:[{sender: searched_id}, {receiver: searched_id}]}},
                 {$sort: {date: -1}},
                 {$group: {"_id": {sender: "$sender", receiver: "$receiver"}}},
                  function(err, docs){
    console.log(JSON.stringify(docs));
});

此查询为我提供了与某个人交谈过的所有人员,但它的顺序不正确,如果我更改排序顺序,它会为我提供准确的结果。

如何按日期对 collection 进行排序?

鉴于该数据集:

{ "_id" : 1, "sender" : 1, "receiver" : 2, "date" : ISODate("2015-05-30T15:14:48Z") }
{ "_id" : 2, "sender" : 2, "receiver" : 1, "date" : ISODate("2015-05-30T15:16:28Z") }
{ "_id" : 3, "sender" : 1, "receiver" : 3, "date" : ISODate("2015-05-30T15:20:00Z") }
{ "_id" : 4, "sender" : 1, "receiver" : 2, "date" : ISODate("2015-05-30T15:21:48Z") }
{ "_id" : 5, "sender" : 3, "receiver" : 2, "date" : ISODate("2015-05-30T15:25:15Z") }
{ "_id" : 6, "sender" : 4, "receiver" : 1, "date" : ISODate("2015-05-30T15:30:05Z") }

显然您只想保留 最近的 联系人,您可以使用以下方式达到您想要的结果:

> searched_id = 1
> db.test.aggregate([
 {$match: {$or: [{sender: searched_id}, {receiver: searched_id}]}},
 {$project: { _id: 1, date: 1,
              interlocutor: {$cond: [{$eq: ["$sender", searched_id]},"$receiver","$sender"]}}},
 {$group: {_id: "$interlocutor", date: {$max: "$date"}}},
 {$sort: {date: -1}},
])
  • $match阶段是一个简单的过滤器;
  • $project阶段会将对话者推断为发送者或接收者;
  • 每组中的$group stage will group multiple results per interlocutor, keeping the most recent call ($max)日期;
  • 最后 $sort 阶段将生成的文档从最新到最旧排序。

运行那个管道,它会return:

{ "_id" : 4, "date" : ISODate("2015-05-30T15:30:05Z") }
{ "_id" : 2, "date" : ISODate("2015-05-30T15:21:48Z") }
{ "_id" : 3, "date" : ISODate("2015-05-30T15:20:00Z") }