mongodb - 如何在Mongo中独立地按日期和时间过滤?
问题描述
如何在Mongo中独立地按日期和时间过滤?
我希望能够在数据库中独立保存日期和日期,我可以在其中独立地按日期和时间进行过滤。
我应该只有一个保存日期对象的字段吗?如果是的话,我怎么能按时间过滤。我如何获得有关记录的统计信息,例如日期从 01/05/2017 到 15/03/2018并且记录的时间应该在下午 3 点到下午 5 点之间(所以记录的日期为 12/ 03/2018 和下午 5:05 的时间不应包括在内)。
解决方案
这里要考虑的重要一点是,您实际上需要在这里继续使用“常规查询运算符”,否则您将大大降低性能。这个想法是始终编写一个实际上可以“使用索引”的查询,然后确保您有索引。
因此,“天”的选择是一个标准的范围查询,剩下的只是考虑到“已经选择”的文档,首先通过正确指定标准查询条件,用“计算”过滤表达式:
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
查询运算符来评估聚合框架逻辑运算符和日期运算符。日期范围表达式的常规比较运算符。
较低版本 - 聚合和 $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
管道阶段应用。日期范围表达式 withing 的相同正则比较运算符$match
。
所有版本 - $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}`
})
将 JavaScript 评估与$where
. 除非已明确禁用服务器端脚本,否则在所有版本中都可用。请注意,“相同”和常规比较运算符用于日期范围的主要选择。
在所有情况下,都必须表达“标准查询运算符”条件“first”。如果没有这个,MongoDB 就无法使用数据中存在的索引,并且需要扫描集合中的每个文档以计算条件并查看是否返回文档。
将“标准运算符”条件与$gte
and$lt
范围相加确保索引可以使用,而剩余的“计算”逻辑表达式仅实际应用于那些已经满足“第一个”条件的文档。
对于“奖金”,您甚至可以将时间限制放在“天”本身上,因此您甚至不考虑分别在开始和结束日期下午 3 点之前或下午 5 点之后的时间:
"date": { "$gte": new Date("2017-05-01T15:00"), "$lt": new Date("2018-03-16T17:00") }
因此,在可能的情况下,始终“使用索引”并确保您的查询表达式实际上是为使用它们而构建的,而不是其他不使用的形式。
注意这里的一般逻辑是这里所有呈现的解决方案的“性能”应该按照呈现的顺序进行扩展,从
$expr
最好到$where
最差。然而,在目前的写作中,MongoDB 3.6 版本似乎出现了回归,实际上它$where
通常比实际使用本机运算符的对应版本表现更好。然而,这不应该是“持续”的情况,应该得到解决,因此通常建议您使用原生运算符组合,而不是 JavaScript 逻辑与
$where
.
推荐阅读
- docker - 在 docker 中运行的红隼无法提供静态内容
- regex - 使用正则表达式仅匹配百分比中的数字
- python - QSqlTableModel setFilter 参数太多
- flutter - Mockito 重置通话计数?
- symfony - 在一个带有 encore 的 symfony 项目中,如何设置 Jest?
- java - 如何在 Selenium-java 中将页面对象与代码逻辑分开
- php - 正则表达式 php 中替代值的 Preg_match 不起作用
- windows - 由于“无法构建存档”而无法构建任何依赖项
- docker - 如何更新在我的 ddev 容器中使用的作曲家版本?
- python - Django:每次我开发我的 django 应用程序时都必须打开虚拟环境吗