MongoDB中用gte和lte进行字符串时间范围查询的问题
解决MongoDB字符串格式时间范围查询问题
你之前的查询失效是因为LAST_UPDATED是字符串类型,MongoDB对字符串的比较是字典序,而非时间顺序。比如字符串"10:00"会被判定为小于"8:00"(因为字符'1'的ASCII码小于'8'),导致跨小时的范围查询逻辑出错。
以下是两种无需修改字段格式的解决方案:
方案1:使用聚合管道处理时间转换
利用聚合管道的字符串分割、类型转换和数值计算,将时间转换为总分钟数后再做范围筛选,逻辑清晰且易维护:
db.collection_name.aggregate([ // 拆分出时间部分并分割小时、分钟 { $addFields: { timeSplit: { $split: [{ $arrayElemAt: [{ $split: ["$LAST_UPDATED", " "] }, 1] }, ":"] } } }, // 计算时间对应的总分钟数(小时*60+分钟) { $addFields: { totalMinutes: { $add: [ { $multiply: [{ $toInt: { $arrayElemAt: ["$timeSplit", 0] } }, 60] }, { $toInt: { $arrayElemAt: ["$timeSplit", 1] } } ] } } }, // 筛选总分钟数在目标范围内的文档 { $match: { totalMinutes: { $gte: 390, $lte: 525 } // 6:30=390分钟,8:45=525分钟 } }, // 移除临时生成的辅助字段(可选) { $project: { timeSplit: 0, totalMinutes: 0 } } ])
方案2:使用$expr在find中直接查询
如果不想用聚合管道,可借助MongoDB 3.6+支持的$expr表达式,在find中嵌入时间转换逻辑:
db.collection_name.find({ $expr: { $and: [ { $gte: [ { $add: [ { $multiply: [{ $toInt: { $arrayElemAt: [{ $split: [{ $arrayElemAt: [{ $split: ["$LAST_UPDATED", " "] }, 1] }, ":"] }, 0] } }, 60] }, { $toInt: { $arrayElemAt: [{ $split: [{ $arrayElemAt: [{ $split: ["$LAST_UPDATED", " "] }, 1] }, ":"] }, 1] } } ] }, 390 ] }, { $lte: [ { $add: [ { $multiply: [{ $toInt: { $arrayElemAt: [{ $split: [{ $arrayElemAt: [{ $split: ["$LAST_UPDATED", " "] }, 1] }, ":"] }, 0] } }, 60] }, { $toInt: { $arrayElemAt: [{ $split: [{ $arrayElemAt: [{ $split: ["$LAST_UPDATED", " "] }, 1] }, ":"] }, 1] } } ] }, 525 ] } ] } })
关键说明
由于你的集合每天凌晨清理数据,所有文档的日期部分一致,因此只需要提取时间部分转换为总分钟数即可,无需处理日期差异。两种方案都是通过将字符串时间转换为可正确比较的数值,避免了字典序比较的逻辑错误。
内容的提问来源于stack exchange,提问作者Kanojian
相关产品推荐
相关产品推荐

