Mongoose分组联查实现类似WhatsApp首页的会话用户列表查询
Mongoose 实现会话列表查询方案
完整实现代码
const mongoose = require('mongoose'); const Message = require('./models/message'); // 替换为你实际的Message模型引入路径 async function getUserChatList(currentUserId) { // 转换为ObjectId类型避免匹配失败 const targetUserId = new mongoose.Types.ObjectId(currentUserId); const rawChatList = await Message.aggregate([ // 1. 过滤所有和当前用户相关的收发消息 { $match: { $or: [ { from: targetUserId }, { to: targetUserId } ] } }, // 2. 按发送时间倒序排列,保证最新消息在分组时排在首位 { $sort: { date: -1 } }, // 3. 生成会话唯一标识、标记聊天对方 { $addFields: { // 将两个用户ID按大小排序后拼接,保证互发消息归为同一个会话 sessionKey: { $concat: [ { $toString: { $min: ["$from", "$to"] } }, "-", { $toString: { $max: ["$from", "$to"] } } ] }, // 识别当前会话的对方用户ID contactUser: { $cond: { if: { $eq: ["$from", targetUserId] }, then: "$to", else: "$from" } } } }, // 4. 按会话分组,每个会话只保留最新一条消息 { $group: { _id: "$sessionKey", latestMessage: { $first: "$$ROOT" }, contactUser: { $first: "$contactUser" } } }, // 可选:调整返回结构,更贴合前端使用习惯 { $replaceRoot: { newRoot: { $mergeObjects: ["$latestMessage", { contactUser: "$contactUser" }] } } } ]); // 手动populate关联的用户信息,支持from、to、对方用户三个字段的关联查询 const populatedChatList = await Message.populate(rawChatList, [ { path: "from", model: "Users" }, { path: "to", model: "Users" }, { path: "contactUser", model: "Users" } ]); return populatedChatList; }
优化建议
- 给
from、to、date三个字段添加联合索引,数据量大时查询性能可提升数倍 - 如果不需要完整消息字段,可在
$group阶段仅保留需要的messageContent、date、status等字段,减少数据传输开销 - 可额外添加未读消息统计逻辑,在
$group阶段用$sum统计未读消息数量即可
内容的提问来源于stack exchange,提问作者Huzaifa Azim
相关产品推荐
相关产品推荐

