MongoDB聚合$match中$and匹配多日期$eq表达式返回空数组问题
问题解决:MongoDB匹配两个月份的销售数据
核心错误分析
你的查询返回空数组,主要存在两个关键问题:
- 逻辑运算符误用:使用
$and要求单条文档的createdAt同时匹配两个不同月份的年月,这显然不可能——单条文档只能属于一个月份,应该用$or替代$and。 - 日期变量计算错误:
Date是可变类型,setMonth会直接修改原date对象,导致lastMonth和prevMonth的实际值与预期不符。
修复步骤
1. 修正日期变量的计算
避免修改原date对象,通过创建新Date实例生成目标月份(建议设为当月第一天,规避日期溢出问题,比如3月31日减1月会自动转为3月3日):
const date = new Date(); // 上个月(例:当前是2023年2月,则为2023年1月1日) const lastMonth = new Date(date.getFullYear(), date.getMonth() - 1, 1); // 上上个月(例:当前是2023年2月,则为2022年12月1日) const prevMonth = new Date(date.getFullYear(), date.getMonth() - 2, 1);
2. 修正$match阶段的逻辑
将$and替换为$or,匹配属于prevMonth年月 或 lastMonth年月的文档:
{ $match: { $expr: { $or: [ { $eq: [ { $dateFromParts: { month: { $month: '$createdAt' }, year: { $year: '$createdAt' } } }, { $dateFromParts: { month: { $month: prevMonth }, year: { $year: prevMonth } } } ] }, { $eq: [ { $dateFromParts: { month: { $month: '$createdAt' }, year: { $year: '$createdAt' } } }, { $dateFromParts: { month: { $month: lastMonth }, year: { $year: lastMonth } } } ] } ] } } }
可选优化:更高效的匹配方式
如果createdAt字段有索引,推荐用范围查询替代$expr,利用索引提升查询效率:
// 计算每个月份的起始/结束日期 const prevMonthStart = new Date(prevMonth.getFullYear(), prevMonth.getMonth(), 1); const prevMonthEnd = new Date(prevMonth.getFullYear(), prevMonth.getMonth() + 1, 1); const lastMonthStart = new Date(lastMonth.getFullYear(), lastMonth.getMonth(), 1); const lastMonthEnd = new Date(lastMonth.getFullYear(), lastMonth.getMonth() + 1, 1); // 匹配目标月份范围内的文档 { $match: { createdAt: { $or: [ { $gte: prevMonthStart, $lt: prevMonthEnd }, { $gte: lastMonthStart, $lt: lastMonthEnd } ] } } }
内容的提问来源于stack exchange,提问作者Tai Abrahams
相关产品推荐
相关产品推荐

