MongoDB聚合Lookup:多条件匹配及当前用户_id获取方法
解决MongoDB Lookup多条件关联匹配问题
需求说明
需要在User集合的聚合Lookup操作中,关联Chats集合,匹配Chat文档的from或to字段,使其分别对应当前用户的_id(作为发送方或接收方),并为用户文档添加chatHistory字段存储关联的聊天记录。
示例集合数据
User集合
[{ _id: { $oid: "64428badffd445ba3c11a9b4" }, firstName: "test", lastName: "user", type: { $numberInt: "2" }, email: "test@user.com", password: "$2a$10$gm25OtxxAGl3Cj4V.ZoQ0OngID0eAfaAdQh5sQeKJ0aTyoVukChkG", createdAt: { $date: { $numberLong: "1682082733141" } }, updatedAt: { $date: { $numberLong: "1682082733141" } }, __v: { $numberInt: "0" }, }]
Chats集合
[{ _id: { $oid: "644f892004492f9c01296861" }, from: { $oid: "64428badffd445ba3c11a9b4" }, to: { $oid: "644a07431babb4a2df531f2a" }, message: "hello", createdAt: { $date: { $numberLong: "1682934048968" } }, updatedAt: { $date: { $numberLong: "1682934048968" } }, __v: { $numberInt: "0" }, }]
错误代码示例
用户尝试的两种错误实现:
初始代码
const recentChats = await User.aggregate([ { $lookup: { from: "chats", as: "chatHistory", pipeline: [ { $match: { $or: [{ from: req.params.id }, { to: "$$id" }], }, }, ], }, }, ]);
尝试修改后的错误代码
const recentChats = await User.aggregate([ { $lookup: { from: "chats", as: "chatHistory", let: { vars: { id: { $getField: "_id" } }, }, pipeline: [ { $match: { $or: [{ from: req.params.id }, { to: "$$id" }], }, }, ], }, }, ]);
正确实现方式
代码实现
// 先将req.params.id转换为ObjectId,确保类型匹配 const userId = mongoose.Types.ObjectId(req.params.id); const recentChats = await User.aggregate([ { $lookup: { from: "chats", as: "chatHistory", // 正确定义lookup内部变量,直接引用当前User文档的_id let: { userId: "$_id" }, pipeline: [ { $match: { // 使用$expr来引用lookup传递的变量,同时匹配两个条件 $expr: { $or: [ { $eq: ["$from", userId] }, { $eq: ["$to", "$$userId"] } ] } } } ], }, }, ]);
关键修正点
- 变量定义错误:之前的
let里嵌套vars是错误语法,let需要直接声明键值对形式的变量,这里用userId: "$_id"直接引用当前User文档的_id。 - 类型匹配问题:
req.params.id是字符串类型,而MongoDB文档的_id是ObjectId类型,需要先转换为ObjectId避免匹配失败。 - 条件匹配语法:在子管道的
$match中,引用let定义的变量需要使用$expr包裹,否则无法识别$$userId这类变量引用。
内容的提问来源于stack exchange,提问作者Pratik Sangani
相关产品推荐
相关产品推荐

