MongoDB对比同文档日期字段查询匹配记录报错排查
问题根因
你的查询报错且结果不符合预期,核心是两个写法错误:
- 普通
$match的常规查询语法仅支持匹配固定常量,不会解析$date_created这类字段引用,你写的ISODate('$date_created')只会把字符串'$date_created'当成传入的日期参数,完全无法读取当前文档的date_created字段值,部分版本会直接抛出字段未定义错误。 ISODate()是日期类型构造函数,仅支持传入固定格式的日期字符串生成固定日期值,本身不支持动态读取文档字段做运算。
同文档跨字段值比较,必须使用聚合表达式运算符实现。
正确查询写法
推荐写法(MongoDB 3.6及以上版本,性能最优)
使用$expr运算符在$match阶段直接支持聚合表达式的字段比较,不需要额外阶段:
db.getCollection("collection_name").aggregate([ { $match: { status: '1', $or: [ // 匹配date_modified字段不存在的记录 { date_modified: { $exists: false } }, // 匹配date_modified晚于date_created的记录 { $expr: { $gt: ["$date_modified", "$date_created"] } } ] } } ])
说明:
$expr允许在$match中直接通过$字段名引用当前文档的字段值做运算,两个ISODate类型字段可以直接用$gt/$lt比较先后,不需要额外做类型转换。
低版本兼容写法(MongoDB 3.6以下)
如果你的MongoDB版本低于3.6不支持$expr,可以先通过$addFields生成比较结果的辅助字段,再做匹配:
db.getCollection("collection_name").aggregate([ { $addFields: { _is_modified_later: { $cond: [ { $ifNull: ["$date_modified", false] }, { $gt: ["$date_modified", "$date_created"] }, false ] } } }, { $match: { status: '1', $or: [ { date_modified: { $exists: false } }, { _is_modified_later: true } ] } }, // 可选:移除临时生成的辅助字段 { $project: { _is_modified_later: 0 } } ])
执行效果
针对你提供的示例数据,上述查询会准确返回预期的2条记录:
date_modified为2022-06-29的记录:修改时间晚于创建时间,命中比较条件- 无
date_modified字段的记录:命中字段不存在条件 date_modified为2022-06-19的记录:修改时间早于创建时间,会被正确过滤
内容的提问来源于stack exchange,提问作者raj
相关产品推荐
相关产品推荐

