MongoDB聚合查询:查询Session时关联UnreadCount获未读计数失败求解决
问题:查询Session时关联获取UnreadCount未读计数失败
我拥有Session和UnreadCount两个Mongoose模型,未使用引用关联机制,需要在查询Session时获取对应的未读计数,但使用$lookup聚合操作未得到预期结果。以下是模型定义及执行的聚合代码:
模型定义
var UnreadCountSchema = new mongoose.Schema({ userId: { type: String, required: true }, sessionId: { type: String, required: true}, unreadCount: { type: Number, required: true, default: 0 }, isDeleted: { type: Boolean, required: true, default: 0 }, }, { timestamps: true }); module.exports = mongoose.model("UnreadCount", UnreadCountSchema); var SessionSchema = new mongoose.Schema({ name: { type: String, required: false }, subject: { type: String, required: false }, sessionCode: { type: String, required: false }, }, { timestamps: true }); module.exports = mongoose.model("Session", SessionSchema);
原聚合代码
const response = await SessionModel.aggregate([ { $match: query, }, { $lookup: { from: "UnreadCount", localField: "_id", foreignField: "sessionId", as: "unreadCounts", }, }, { $addFields: { unreadCount: { $cond: { if: { $gt: [{ $size: "$unreadCounts" }, 0] }, then: { $arrayElemAt: ["$unreadCounts.unreadCount", 0] }, else: 0, }, }, }, }, // Optionally sort the sessions by lastMessage createdAt // { $sort: { "lastMessage.createdAt": -1 } }, ])
解决方法
1. 修正集合名称
Mongoose默认会将模型名转换为小写复数形式作为集合名称,因此UnreadCount模型对应的集合实际是unreadcounts,而非UnreadCount,这是导致关联失败的常见原因之一。
2. 解决类型不匹配问题
Session的_id是MongoDB默认的ObjectId类型,而UnreadCount的sessionId定义为String类型,两者类型不匹配会导致关联逻辑失效。有两种修复方式:
- 方式一:修改UnreadCount模型的
sessionId类型为ObjectId,同时关联Session模型:sessionId: { type: mongoose.Schema.Types.ObjectId, ref: 'Session', required: true}, - 方式二:在聚合管道中先将Session的
_id转为字符串,再进行关联。
3. 过滤未删除记录
UnreadCount包含isDeleted字段,关联时应只获取未删除的有效记录,避免无效数据干扰结果。
修复后的聚合代码(以方式二为例,不修改模型)
const response = await SessionModel.aggregate([ { $match: query }, // 将Session的_id转为字符串,匹配UnreadCount的sessionId { $addFields: { sessionIdStr: { $toString: "$_id" } } }, { $lookup: { from: "unreadcounts", // 修正为正确的集合名 let: { sessionId: "$sessionIdStr" }, pipeline: [ { $match: { $expr: { $eq: ["$sessionId", "$$sessionId"] }, isDeleted: false // 过滤未删除的记录 } } ], as: "unreadCounts" } }, { $addFields: { unreadCount: { $cond: { if: { $gt: [{ $size: "$unreadCounts" }, 0] }, then: { $arrayElemAt: ["$unreadCounts.unreadCount", 0] }, else: 0 } }, // 移除临时字段sessionIdStr sessionIdStr: "$$REMOVE" } } ])
额外说明
如果一个Session对应多个UnreadCount(比如不同用户的未读计数),当前代码只取第一条的计数。如果需要获取特定用户的未读计数,可以在$lookup的pipeline中添加userId过滤条件:
$match: { $expr: { $eq: ["$sessionId", "$$sessionId"] }, isDeleted: false, userId: "目标用户ID" // 添加用户ID过滤 }
内容的提问来源于stack exchange,提问作者Lakshmanan M
相关产品推荐
相关产品推荐

