Mongoose多关联字段查询:筛选关联文档isActive为true的通知
方案1:基于现有populate逻辑改造(改动最小,易理解)
你可以在populate时添加match筛选条件,只拉取isActive: true的关联文档,不符合条件的关联字段会返回null,之后再过滤掉关联字段全为null的通知即可,同时要调整计数逻辑保证分页总数正确:
let totalItems; const query = { organisationId: organisationId }; Notification.find(query) // populate时新增isActive筛选条件 .populate({ path: "eventId", match: { isActive: true } }) .populate({ path: "newsId", match: { isActive: true } }) .populate({ path: "funeralNewsId", match: { isActive: true } }) .lean() .then(allNotifications => { // 过滤出关联文档有效的通知 const validNotifications = allNotifications.filter(item => { return item.eventId || item.newsId || item.funeralNewsId }) totalItems = validNotifications.length // 分页+排序处理 const paginatedNotifications = validNotifications .sort((a,b) => b.creationDate - a.creationDate) .slice(page * limit, (page + 1) * limit) res.status(200).json({ notifications: paginatedNotifications, totalItems }) }) .catch((err) => { next(err); });
提示:如果你的
type字段取值和关联类型对应(比如type为event时仅eventId有值),可以把filter条件替换为对应type的判断,过滤效率更高。
方案2:使用聚合查询(性能更高,适合数据量大的场景)
直接通过MongoDB聚合的$lookup关联对应集合并做条件筛选,一次查询完成所有逻辑,避免内存中过滤的性能损耗:
const query = { organisationId: organisationId }; Notification.aggregate([ { $match: query }, // 关联Events集合,仅拉取isActive为true的文档 { $lookup: { from: "events", // 此处为MongoDB集合的实际名称,一般是模型名小写加s,如有出入自行调整 localField: "eventId", foreignField: "_id", pipeline: [{ $match: { isActive: true } }], as: "eventInfo" } }, // 关联News集合 { $lookup: { from: "news", localField: "newsId", foreignField: "_id", pipeline: [{ $match: { isActive: true } }], as: "newsInfo" } }, // 关联FuneralNews集合 { $lookup: { from: "funeralnews", // 此处确认集合实际名称 localField: "funeralNewsId", foreignField: "_id", pipeline: [{ $match: { isActive: true } }], as: "funeralNewsInfo" } }, // 过滤掉三个关联结果都为空的无效通知 { $match: { $or: [ { "eventInfo.0": { $exists: true } }, { "newsInfo.0": { $exists: true } }, { "funeralNewsInfo.0": { $exists: true } } ] } }, // 排序、分页、计数统一处理 { $sort: { creationDate: -1 } }, { $facet: { totalItems: [{ $count: "count" }], notifications: [ { $skip: page * limit }, { $limit: limit }, // 把关联数组转成对象,和之前populate的返回格式保持一致 { $addFields: { eventId: { $first: "$eventInfo" }, newsId: { $first: "$newsInfo" }, funeralNewsId: { $first: "$funeralNewsInfo" } } }, // 移除临时生成的关联字段 { $unset: ["eventInfo", "newsInfo", "funeralNewsInfo"] } ] } }, // 处理无匹配数据时的计数默认值 { $addFields: { totalItems: { $ifNull: [{ $first: "$totalItems.count" }, 0] } } } ]) .then(result => { const { notifications, totalItems } = result[0] res.status(200).json({ notifications, totalItems }) }) .catch(err => next(err))
内容的提问来源于stack exchange,提问作者artsnr
相关产品推荐
相关产品推荐

