MongoDB(Mongoose)查询:如何提取两字段的唯一用户ObjectID?
解决MongoDB聚合提取唯一对话用户ID的问题
你的问题出在$setUnion的使用方式上:$from是单个ObjectId值,而$to是数组,$setUnion要求两个输入都是数组类型,所以直接用$setUnion: ["$from", "$to"]没法正确合并去重。下面是修正后的聚合查询方案:
完整聚合代码
const currentUserId = new mongoose.Types.ObjectId(req.user.id); const uniqueUsers = await Message.aggregate([ // 匹配当前用户参与的所有消息 { $match: { $or: [ { from: currentUserId }, { to: { $in: [currentUserId] } } ] } }, // 将单个from字段转为数组,和to数组合并成所有参与者数组 { $addFields: { allParticipants: { $concatArrays: [[ "$from" ], "$to"] } } }, // 拆分参与者数组,每条文档对应一个用户ID { $unwind: "$allParticipants" }, // 全局去重收集所有唯一用户ID { $group: { _id: null, uniqueUserIds: { $addToSet: "$allParticipants" } } }, // 移除当前用户自己的ID,得到最终对话列表 { $project: { _id: 0, uniqueConversations: { $setDifference: [ "$uniqueUserIds", [ currentUserId ] ] } } } ]); // 结果会在uniqueUsers[0].uniqueConversations中 console.log(uniqueUsers[0].uniqueConversations);
代码解释
- $addFields阶段:用
$concatArrays把单个的from包装成数组,再和to数组合并,得到包含这条消息所有参与者的数组allParticipants。 - $unwind阶段:将数组拆分成多条单元素文档,为后续全局去重做准备。
- $group阶段:用
$addToSet收集所有用户ID,自动实现全局去重。 - $project阶段:用
$setDifference从唯一ID数组中移除当前用户自己的ID,直接得到需要的对话用户列表。
用你的示例数据测试,最终会得到:
["671175392a0bcfdb66f83401", "6708368712a817cd73810b5e"]
完全符合你后续移除当前用户ID的需求。
内容的提问来源于stack exchange,提问作者bchow2001
相关产品推荐
相关产品推荐

