如何用Mongoose在MongoDB中按条件筛选数组内关联文档
问题:筛选符合状态、日期条件的用户通知
需求
仅获取符合req.query中指定状态、from_date和to_date条件的用户通知。
数据模型
User Schema
const userSchema = mongoose.Schema({ email: { type: String, required: true }, password: { type: String, minlength: 8, required: true }, notifications: [{ notification: { type: mongoose.Schema.Types.ObjectId, ref: "Notification" }, status: { type: String, enum: ["Not Acknowledged", "Acknowledged"], default: "Not Acknowledged" }, }] })
Notification Schema
const notificationSchema = mongoose.Schema({ description: { type: String }, remind_on: { type: Date }, remind_at: { type: Date }, });
问题重现
尝试以下代码后,返回的是用户的全部通知,没有按条件筛选:
const statusQuery = {}; if(status) { statusQuery.match = { 'notifications.status': status } } const searchNotifications = await User.findById(user._id) .populate({ path: "notifications", ...statusQuery, populate: { path: "notification", populate: [ { path: "assignee", select: "first_name last_name" }, { path: "case", select: "case_id" }, ], }, }) .select("notifications");
代码逻辑:通过用户ID查询文档后,在populate阶段添加筛选条件。
问题原因
populate筛选notifications数组时,match的路径写错了——当前上下文是数组中的单个子文档,不需要写'notifications.status',直接用status即可。- 没有添加日期范围的筛选逻辑,无法过滤
from_date和to_date对应的通知。
修复后的代码
// 初始化用户通知子文档的筛选条件 const notificationFilter = {}; // 处理状态筛选 if (status) { notificationFilter.status = status; } // 初始化关联Notification文档的日期筛选条件 const nestedNotificationFilter = {}; // 处理起始日期(这里以remind_on为例,可根据需求换成remind_at) if (from_date) { nestedNotificationFilter.remind_on = { ...nestedNotificationFilter.remind_on, $gte: new Date(from_date) }; } // 处理结束日期 if (to_date) { nestedNotificationFilter.remind_on = { ...nestedNotificationFilter.remind_on, $lte: new Date(to_date) }; } const searchNotifications = await User.findById(user._id) .populate({ path: "notifications", // 筛选用户通知子文档的状态 match: notificationFilter, populate: { path: "notification", // 筛选关联通知的日期范围 match: nestedNotificationFilter, populate: [ { path: "assignee", select: "first_name last_name" }, { path: "case", select: "case_id" }, ], }, }) .select("notifications");
关键说明
- 筛选用户的
notifications数组元素时,match直接使用子文档的字段名(比如status),因为此时MongoDB正在遍历数组中的每个子文档进行匹配。 - 日期筛选需要针对关联的
Notification文档,在内部的populate中添加match条件,注意要将传入的日期字符串转为Date类型,确保MongoDB能正确处理范围查询。 - 如果需要用
remind_at作为日期筛选字段,直接替换代码中的remind_on即可。
内容的提问来源于stack exchange,提问作者Harshil Sharma
相关产品推荐
相关产品推荐

