You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MongoDB聊天集合查询:获取最近联系人、最后消息及未读消息数

问题描述

我的MongoDB chats集合结构如下:

{"_id":"654f4d7cbb027c35a0b90529","msg":"test message","createdat":"2023-11-11T09:46:41.872Z","dateseen":"2023-11-11T09:55:56.596Z","fromid":"eb78a1f79938f5eb193b63fc13b3250","toid":"7b987d98718041abb3b9a85b5c96214a","deleted1":false,"deleted1at":null,"deleted2":false,"deleted2at":null,"type":1}

需要编写聚合查询,传入指定userID后,获取该用户的最近聊天联系人、最后一条消息以及未读消息数量。期望输出格式如下:

{"body":[{"id":"c5e8b02a94984fe38e7ff35131890b55","unSeenMsgCount":0,"lastMessage":{"fromId":"eb78a1f74f274353b63fc13b3250","toId":"c5e8b02a94984fe7ff35131890b55","message":"string","dateSent":1704889808607,"type":1}}],"header":null}

我尝试了以下聚合代码,但存在未读消息统计错误、同一联系人生成两条聊天记录的问题,请求修正:

db.collection.aggregate([
    {"$match":{"$or":[{"fromid":userID,"deleted1":false},{"toid":userID,"deleted2":false}]}},
    {"$group":{
        "_id":{"$cond":{
            "if":{"$or":[
                {"$and":[{"$eq":["$fromid",userID]},{"$ne":["$toid",userID]}]},
                {"$and":[{"$eq":["$toid",userID]},{"$ne":["$fromid",userID]}]}
            ]},
            "then":"$toid","else":"$fromid"
        }},
        "lastMessage":{"$last":{"$cond":{
            "if":{"$or":[
                {"$and":[{"$eq":["$toid",userID]},{"$ne":["$fromid",userID]}]},
                {"$and":[{"$eq":["$fromid",userID]},{"$ne":["$toid",userID]}]}
            ]},
            "then":"$$ROOT","else":null
        }}},
        "unseenCount":{"$sum":{"$cond":{
            "if":{"$and":[{"$eq":["$toid",userID]},{"$eq":["$dateseen",null]}]},
            "then":1,"else":0
        }}}
    }},
    {"$sort":{"lastMessage.createdat":-1}},
    {"$replaceRoot":{"newRoot":{"$mergeObjects":["$lastMessage",{"unSeenMsgCount":"$unseenCount"}]}}},
    {"$skip":offset},{"$limit":limit}
])
修正后的聚合查询
db.chats.aggregate([
    // 过滤当前用户相关且未被自己删除的消息
    {
        "$match": {
            "$or": [
                {"fromid": userID, "deleted1": false},
                {"toid": userID, "deleted2": false}
            ]
        }
    },
    // 提前计算对方ID和未读标记
    {
        "$addFields": {
            "peerId": {
                "$cond": [{"$eq": ["$fromid", userID]}, "$toid", "$fromid"]
            },
            "isUnseen": {
                "$and": [
                    {"$eq": ["$toid", userID]},
                    {"$eq": ["$dateseen", null]}
                ]
            }
        }
    },
    // 按联系人分组,取最新消息、统计未读数量
    {
        "$group": {
            "_id": "$peerId",
            "lastMessage": {"$max": {"date": "$createdat", "doc": "$$ROOT"}},
            "unSeenMsgCount": {"$sum": {"$cond": ["$isUnseen", 1, 0]}}
        }
    },
    // 提取最新消息的原始文档
    {
        "$addFields": {
            "lastMessage": "$lastMessage.doc"
        }
    },
    // 按消息时间倒序排序
    {
        "$sort": {"lastMessage.createdat": -1}
    },
    // 映射为期望的输出字段格式
    {
        "$project": {
            "_id": 0,
            "id": "$_id",
            "unSeenMsgCount": "$unSeenMsgCount",
            "lastMessage": {
                "fromId": "$lastMessage.fromid",
                "toId": "$lastMessage.toid",
                "message": "$lastMessage.msg",
                "dateSent": {"$toLong": {"$toDate": "$lastMessage.createdat"}},
                "type": "$lastMessage.type"
            }
        }
    },
    // 分页处理
    {"$skip": offset},
    {"$limit": limit},
    // 包裹成指定的输出结构
    {
        "$group": {
            "_id": null,
            "body": {"$push": "$$ROOT"}
        }
    },
    {
        "$project": {
            "_id": 0,
            "body": 1,
            "header": null
        }
    }
])
修正说明
  • 解决联系人重复问题:通过$addFields提前计算统一的peerId(对方用户ID),确保每个联系人只会生成一条分组记录,避免原逻辑中冗余条件导致的分组错误。
  • 修正未读消息统计:新增isUnseen字段明确标记未读消息(当前用户为接收方且dateseen为空),统计时直接累加该标记,避免原逻辑的判断遗漏。
  • 准确获取最新消息:改用$max结合消息时间戳获取最新消息,比依赖聚合顺序的$last更可靠,确保拿到的是时间最晚的消息。
  • 对齐输出格式:通过$project严格映射字段名(如msg转message、createdat转时间戳dateSent),最后通过分组包裹成body和header的指定结构。

内容的提问来源于stack exchange,提问作者Mevo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 08:00:35