MongoDB 4.4中如何生成到期日提前1/3个月的计算字段?
MongoDB 4.4 日期偏移查询优化方案(字符串日期场景)
需求明确
需要从集合中筛选满足以下任一条件的记录:
- 字段
expiryDate(YYYY-MM-DD字符串格式)等于当前日期 expiryDate等于当前日期加1个月(即当前日期是到期日提前1个月的提醒节点)expiryDate等于当前日期加3个月(即当前日期是到期日提前3个月的提醒节点)
由于MongoDB 4.4不支持$dateAdd,且直接用毫秒计算月份会因每月天数不同产生误差,需要用日期拆分重组的方式实现精准的月份偏移。
优化后的聚合查询
db.getCollection('torjak_requests').aggregate([ // 前置过滤:缩小处理范围,提升性能 { $match: { expiryDateS: { $gte: { $dateToString: { format: "%Y-%m-%d", date: new Date() } }, $lte: { $dateToString: { format: "%Y-%m-%d", date: new Date(new Date().setMonth(new Date().getMonth() + 3)) } } } // 可添加其他业务过滤条件 } }, // 合并日期转换与目标日期计算 { $addFields: { // 字符串日期转ISO格式 expiryDate: { $dateFromString: { dateString: "$expiryDateS" } }, // 生成当前日期+1个月的目标字符串 target1MonthLater: { $dateToString: { format: "%Y-%m-%d", date: { $dateFromParts: { year: { $year: new Date() }, month: { $add: [{ $month: new Date() }, 1] }, day: { $dayOfMonth: new Date() }, hour: 0, minute: 0, second: 0, millisecond: 0 } } } }, // 生成当前日期+3个月的目标字符串 target3MonthsLater: { $dateToString: { format: "%Y-%m-%d", date: { $dateFromParts: { year: { $year: new Date() }, month: { $add: [{ $month: new Date() }, 3] }, day: { $dayOfMonth: new Date() }, hour: 0, minute: 0, second: 0, millisecond: 0 } } } } } }, // 匹配符合条件的记录 { $match: { $or: [ { expiryDateS: { $dateToString: { format: "%Y-%m-%d", date: new Date() } } }, { expiryDateS: "$target1MonthLater" }, { expiryDateS: "$target3MonthsLater" } ] } }, // 清理临时字段 { $project: { expiryDate: 0, target1MonthLater: 0, target3MonthsLater: 0 } } ])
优化说明
- 前置过滤减少数据量:先通过
$match筛选出日期范围在当前日到当前日+3个月内的记录,避免无意义的后续计算。 - 合并聚合阶段:将日期转换、目标日期计算合并到同一个
$addFields阶段,减少阶段切换的开销。 - 精准日期偏移:用
$dateFromParts拆分重组日期,直接实现月份加减,避免毫秒计算的天数误差。 - 统一日期精度:指定时分秒为0,确保与原字符串日期的精度一致,避免因时间部分差异导致匹配失败。
针对你现有方案的精简优化
如果需要基于记录的expiryDate生成提前日期字段,可以合并步骤减少冗余:
db.getCollection('torjak_requests').aggregate([ { $match: { /* 业务过滤条件 */ } }, { $addFields: { expiryDate: { $dateFromString: { dateString: "$expiryDateS" } }, // 一次性生成两个提前日期的字符串 expiryDate1MonthBeforeS: { $dateToString: { format: "%Y-%m-%d", date: { $dateFromParts: { year: { $year: "$expiryDate" }, month: { $add: [{ $month: "$expiryDate" }, -1] }, day: { $dayOfMonth: "$expiryDate" }, hour: 0, minute: 0, second: 0, millisecond: 0 } } } }, expiryDate3MonthsBeforeS: { $dateToString: { format: "%Y-%m-%d", date: { $dateFromParts: { year: { $year: "$expiryDate" }, month: { $add: [{ $month: "$expiryDate" }, -3] }, day: { $dayOfMonth: "$expiryDate" }, hour: 0, minute: 0, second: 0, millisecond: 0 } } } } } }, // 可添加匹配当前日期的逻辑: // { $match: { $or: [{ expiryDateS: currentStr }, { expiryDate1MonthBeforeS: currentStr }, { expiryDate3MonthsBeforeS: currentStr }] } }, { $project: { expiryDate: 0 } } ])
内容的提问来源于stack exchange,提问作者Borgy Manotoy
相关产品推荐
相关产品推荐

