如何将聊天消息文档数组按连续用户分组拆分为多个数组?
解决方案:将连续相同用户的聊天消息分组
场景说明
你已经通过Messages.find().sort({ timestamp: 1 })获取到按时间升序排序的消息列表,现在需要将**连续相同userId**的消息归为独立数组(而非全局按userId合并)。
方法一:应用层(JavaScript)处理排序后的数组
拿到排序后的消息数组后,通过遍历对比当前与前一条消息的userId即可完成分组:
// 假设sortedMessages是你通过find().sort()获取的数组 const sortedMessages = await Messages.find().sort({ timestamp: 1 }).lean(); const groupedMessages = []; if (sortedMessages.length === 0) return groupedMessages; // 初始化第一个分组 let currentGroup = [sortedMessages[0]]; let currentUserId = sortedMessages[0].userId; for (let i = 1; i < sortedMessages.length; i++) { const message = sortedMessages[i]; if (message.userId === currentUserId) { // 同用户消息,加入当前分组 currentGroup.push(message); } else { // 用户切换,存入当前分组并初始化新分组 groupedMessages.push(currentGroup); currentGroup = [message]; currentUserId = message.userId; } } // 加入最后一个分组 groupedMessages.push(currentGroup); console.log(groupedMessages);
执行后会得到你期望的结构:连续相同用户的消息被打包为子数组,顺序与时间排序完全一致。
方法二:MongoDB聚合管道实现(大数据量推荐)
如果数据量较大,直接在数据库层面完成分组能减少传输开销、提升效率。利用$setWindowFields标记连续用户的分组ID,再按ID聚合:
const groupedMessages = await Messages.aggregate([ // 1. 按时间升序排序 { $sort: { timestamp: 1 } }, // 2. 用窗口函数标记连续用户的分组ID { $setWindowFields: { sortBy: { timestamp: 1 }, output: { groupId: { $sum: { $cond: [ { $ne: ["$userId", { $lag: "$userId" }] }, 1, 0 ] } } } } }, // 3. 按分组ID聚合消息 { $group: { _id: "$groupId", messages: { $push: "$$ROOT" } } }, // 4. 按分组ID排序,保证顺序正确 { $sort: { _id: 1 } }, // 5. 整理输出格式 { $project: { _id: 0, messages: 1 } }, { $group: { _id: null, result: { $push: "$messages" } } }, { $project: { _id: 0, result: 1 } } ]); // 最终结果在groupedMessages[0].result中 console.log(groupedMessages[0].result);
管道逻辑说明:
$setWindowFields:通过$lag获取前一条消息的userId,若与当前不同则groupId加1,实现连续用户的分组标记。- 后续的
$group与$sort负责将标记后的消息整理为目标结构。
内容的提问来源于stack exchange,提问作者user3142695
相关产品推荐
相关产品推荐

