获取与MongoDB对话中的最新消息

时间:2018-09-17 14:47:23

标签: javascript node.js mongodb mongoose

我使用 mongo 存储用户的消息。
这是我的收藏模型。

_id            // mongo id of the message
subject        // subject of the message
msg            // message
recipients     // array of users id
sender         // user id
inReplyTo      // id of the message that i'm replying
references     // array of all the ids of the conversation
sended         // date of dispatch

我想列出每页收到30条消息的列表。如果有对话,在列表中,我只希望看到对话的最后一条消息。
我使用猫鼬 nodejs

这些是一次对话的2条消息。

[
       // the first message of the conversation
       {
            "_id" : ObjectId("5b9a7218b83256001799a114"),
            "inReplyTo" : null,
            "references" : [ ],
            "recipients" : [ 1, 2, 3 ],
            "subject" : "Subject of the first message",
            "msg" : "Text of the first message",
            "sender" : 4,
            "sended" : ISODate("2018-09-13T16:20:08.997+02:00"),
        },
        // the reply to the first message
        {
            "_id" : ObjectId("5b9bc0d67d6acc001732a58a"),
            "inReplyTo" : ObjectId("5b9a7218b83256001799a114"),
            "references" : [
                ObjectId("5b9a7218b83256001799a114")
            ],
            "recipients" : [ 4 ],
            "subject" : "FDW: Subject of the first message",
            "msg" : "Text of the reply",
            "sender" : 1,
            "sended" : ISODate("2018-09-14T16:08:22.934+02:00"),
        }
]

如何使用聚合?
还是我必须在查询后过滤它们?又如何?

2 个答案:

答案 0 :(得分:0)

更新1:我更新了我的答案代码以适合您发布的示例数据。该消息将搜索出发送给用户或由用户发送的每条消息,并按会话将其分组,并仅返回每条消息的第一(最后)。

Message.aggregate([
    // Get the first message of each conversation concerning user
    { 
        $match: { 
            $and: [
                {  
                    $or: [
                        { recepient: USER_ID }, // User is in recepients 
                        { sender: USER_ID }     // or the sender
                    ],
                },
            ]
        }
    },
    // Add a conversation field to group them by conversation
    {
        $addFields: {
            conversation: {
                $cond: {
                    if: {
                        $references:  { $exists: false } 
                    },
                    then: '$_id',
                    else: { $arrayElemAt: ['$references', 0]}
                }
            }
        }
    },
    // Sort messages by 'sended' field (descending, most-recent first)
    { 
        $sort: {
            sended: -1
        }
    },

    // Group by conversation, collect only the most recent (first) message of each conversation 
    // { _id: conversation-id#1, message: { ...}},  { _id: conversation-id#2, message: { ...}}, ...
    { 
        $group: { 
            _id:  '$conversation',
            message: { $first: '$$ROOT' }
        }
    }
], function(err, recentMessages) {
    if(err) { /** Handle error.. */ }
});

答案 1 :(得分:0)

这是您要执行的操作:

db.collection.aggregate({
    $match: {
        "recipients": userId // keep only documents where my userId is in the list of recipients
    }
}, {
    $sort: {
        "sended": -1 // sort by "most recent first" - kindly note that it should be "sent" not "sended"
    }
}, {
    $limit: 1 // return no more than one document
})