如何在MongoDB的$match日期筛选中使用$set定义的变量
问题分析与解决方案
原查询的错误点
- 语法无效:
{$date:"$startdate"}写法错误,$date仅能用来解析固定的日期字符串字面量(比如{$date:"2023-12-12T00:00:00Z"}),没办法引用聚合阶段生成的字段或变量。 - 字段引用限制:
$match阶段默认只能用集合原始字段和常量做对比,直接引用$set生成的startdate字段不会生效,必须用$expr开启聚合表达式,才能实现字段间的比较逻辑。 - 时间范围不符需求:原代码里
startdate: new Date()取的是当前时间,和你要筛选「昨日数据」的需求不匹配。
正确的查询写法
写法一:先定义昨日时间变量再筛选
这种方式逻辑清晰,时间变量后续可以复用:
[ { $set: { // 生成昨日00:00:00.000的时间戳 yesterdayStart: { $dateFromParts: { year: { $year: { $subtract: [new Date(), 86400000] } }, month: { $month: { $subtract: [new Date(), 86400000] } }, day: { $dayOfMonth: { $subtract: [new Date(), 86400000] } }, hour: 0, minute: 0, second: 0, millisecond: 0 } }, // 生成昨日23:59:59.999的时间戳 yesterdayEnd: { $dateFromParts: { year: { $year: { $subtract: [new Date(), 86400000] } }, month: { $month: { $subtract: [new Date(), 86400000] } }, day: { $dayOfMonth: { $subtract: [new Date(), 86400000] } }, hour: 23, minute: 59, second: 59, millisecond: 999 } } } }, { $match: { $expr: { $and: [ { $gte: ["$createdate", "$yesterdayStart"] }, { $lte: ["$createdate", "$yesterdayEnd"] } ] } } }, // 可选:如果不需要保留时间变量,移除它们 { $unset: ["yesterdayStart", "yesterdayEnd"] } ]
写法二:直接在$match中计算时间范围(更简洁)
如果不需要复用时间变量,可以直接在筛选阶段计算昨日范围,省去$set步骤:
[ { $match: { $expr: { $and: [ // 昨日0点:当前时间减1天后,截断到当天起始 { $gte: ["$createdate", { $dateTrunc: { date: { $subtract: [new Date(), 86400000] }, unit: "day" } }] }, // 昨日23:59:59.999:今日0点减1毫秒 { $lte: ["$createdate", { $subtract: [{ $dateTrunc: { date: new Date(), unit: "day" } }, 1] }] } ] } } } ]
内容的提问来源于stack exchange,提问作者Jayven Javier
相关产品推荐
相关产品推荐

