多个日期范围用 $or 包裹多个 { date: { $gte: ..., $lte: ... } } 对象即可;每个子条件须完整,字段类型需统一为 Date 并建立索引,否则易导致 COLLSCAN。
$gte 和 $lte 查单个日期范围没问题,但多个范围怎么写?直接用 $or 包裹多个 { date: { $gte: ..., $lte: ... } } 对象即可。MongoDB 支持在同一个字段上对多个互斥区间做并集查询,语法清晰,执行也高效。
常见错误是试图把所有条件塞进一个 $and 或漏写外层 $or,结果查不到数据却以为日期格式有问题。
{ $gte: d1, $lte: d2 } 而不包在 date: { ... } 里ISODate("2024-01-01T00:00:00Z") 或 JavaScript Date 实例,避免字符串比较陷阱null 或缺失,$gte/$lte 默认跳过这些文档;需要包含它们得额外加 { date: { $exists: true } }
$or 查询会不会重复返回同一条文档?不会。MongoDB 的 $or 是逻辑“或”,每条文档只要满足其中任一子条件就返回一次,不因匹配多个条件而重复出现。
例如:文档中 created_at: ISODate("2024-03-15") 同时落在 [2024-03-01, 2024-03-20] 和 [2024-03-10, 2024-03-25] 内,结果集中它只出现一次。
$group 或应用层 dedupe)date 字段上有单字段索引,多个 $gte/$lte 组合也能走索引扫描$match 一层层写在 $match 阶段照样用 $or + 多组 $gte/$lte,和 find() 语法一致。聚合里没有特殊限制,但要注意字段路径写法。
比如查嵌套字段 log.timestamp,子条件得写成 { "log.timestamp": { $gte: ..., $lte: ... } },引号不能省,点号路径必须完整。
$expr 里重复写 $gte——$expr 用于表达式计算,普通范围查询走原生操作符更高效$or 数组再发请求,避免用 $switch 或 $cond 硬编码$facet 比多个 $or 更清晰,但那是另一类需求了stage: COLLSCAN?最常见原因是查询中混用了字符串和 Date 类型。MongoDB 索引对类型敏感,如果集合里部分 date 是字符串(如 "2024-03-15"),部分是 Date,即使你查的是 Date 值,索引也可能失效。
db.collection.find({ date: { $type: "string" } }).limit(1) 快速检查有没有类型混存$gte/$lte 对 String 也能运行,但走的是字典序比较,和时间逻辑不符,且无法利用日期索引Date,例如 db.collection.updateMany({ date: { $type: "string" } }, [{ $set: { date: { $dateFromString: { dateString: "$date" } } }] )
多日期范围本身不是性能瓶颈,类型混乱和缺失索引才是实际卡点。