这里要考虑的重要一点是,您实际上需要在此处继续使用"regular query operators",否则您的性能将大大降低。这个想法是始终编写一个实际上可以“使用索引”的查询,然后确保您有索引。
因此“天”的选择是一个标准的范围查询,剩下的只是考虑到通过正确指定标准“已经选择”的文档来过滤具有“计算”的表达式查询条件first:
MongoDB 3.6 - $expr
db.collection.find({
"date": { "$gte": new Date("2017-05-01"), "$lt": new Date("2018-03-16") },
"$expr": {
"$and": [
{ "$gte": [{ "$hour": "$date" }, 15 ] },
{ "$lt": [{ "$hour": "$date", 17 ] }
]
}
})
使用$expr 查询运算符来评估聚合框架logical operators 和date operators。 Regular comparison operators 用于日期范围表达式。
低版本 - 聚合和 $redact
db.collection.aggregate([
{ "$match": {
"date": { "$gte": new Date("2017-05-01"), "$lt": new Date("2018-03-16") }
}},
{ "$redact": {
"$cond": {
"if": {
"$and": [
{ "$gte": [{ "$hour": "$date" }, 15 ] },
{ "$lt": [{ "$hour": "$date", 17 ] }
]
},
"then": "$$KEEP",
"else": "$$PRUNE"
}
}}
])
相同的聚合表达式,但使用 $redact 管道阶段应用。与$match 相同的日期范围表达式Regular comparison operators。
所有版本 - $where
var startHour = 15,
endHour = 17;
db.collection.find({
"date": { "$gte": new Date("2017-05-01"), "$lte": new Date("2018-03-15") },
"$where": `this.data.getUTCHours() => ${startHour}
&& this.data.getUTCHours() < ${endHour}`
})
通过$where 使用 JavaScript 评估。除非已明确禁用服务器端脚本,否则在所有版本中都可用。请注意,“相同”和Regular comparison operators 用于日期范围的主要选择。
在ALL 情况下,必须表达“标准查询运算符”条件“first”。如果没有这个,MongoDB 将无法使用数据中存在的索引,并且需要扫描集合中的每个文档以计算条件并查看是否返回文档。
在$gte 和$lt 范围内添加“标准运算符”条件确保可以使用索引,而剩余的“计算”逻辑表达式仅实际应用于那些已经满足“第一”的文档条件。
对于“奖励”,您甚至可以将时间限制放在“天”本身上,因此您甚至不用分别考虑开始和结束日期的下午 3 点之前或下午 5 点之后的时间:
"date": { "$gte": new Date("2017-05-01T15:00"), "$lt": new Date("2018-03-16T17:00") }
因此,尽可能始终使用"use an index",并确保您的查询表达式实际构造为使用它们,而不是其他形式。
注意这里的一般逻辑是这里所有提出的解决方案的“性能”应该按呈现顺序扩展,$expr 最好到$where 最差.然而,在目前的写作中,MongoDB 3.6 版本似乎出现了回归,实际上$where 通常比实际使用本机运算符的对应项性能更好。
然而,这不应该是“持续”的情况,应该得到解决,因此通常建议您使用原生运算符组合,而不是 $where 的 JavaScript 逻辑。