如何在Mongo中独立地按日期和时间进行过滤?
我希望能够在数据库中独立保存和日期,我可以按日期和时间独立地过滤。
我是否只有一个保存日期对象的字段?如果是,我怎么能按时间过滤。我如何获得有关记录的统计数据,例如日期为2017年5月1日至15/03/2018 AND 记录的时间应介于下午3点至5点(所以记录日期为12/03/2018,下午5:05的时间不应包括在内。
答案 0 :(得分:2)
这里要考虑的重要一点是,你实际上需要继续在这里使用"regular query operators",否则你的性能会大幅下降。我们的想法是始终编写一个实际上可以“使用索引”的查询,然后确保您的索引存在。
因此,“天”的选择是一个标准范围查询,剩下的只是回到过滤带有“计算”的表达式,考虑到“已经选择”的文件正确指定标准查询条件第一次:
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表示日期范围。
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
管道阶段应用。日期范围表达式Regular comparison operators与$match
相同。
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用于主要选择日期范围。
在所有情况下,必须表达“标准查询运算符”条件“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
最佳为{{}最差的。然而,目前正在编写的MongoDB 3.6版本中似乎有一个回归,实际上$where
通常表现得更好,而实际上使用本机运算符的对应物。这不应该是“正在进行”的情况,但应该得到解决,因此通常建议您使用本机运算符组合而不是
$where
的JavaScript逻辑。
答案 1 :(得分:1)
有如下文件:
db.col.save({ date: new Date("2018-03-02T16:00:00Z") }); // matches
db.col.save({ date: new Date("2018-03-16T16:00:00Z") }); // doesn't match
db.col.save({ date: new Date("2017-05-02T19:00:00Z") }); // doesn't match
db.col.save({ date: new Date("2017-06-15T15:00:00Z") }); // matches
您可以使用$redact将条件指定为表达式。要从Date
中提取一小时,您可以使用$hour运算符:
db.col.aggregate([
{
$redact: {
$cond: {
if: { $and: [
{ $gte: [ "$date", new Date("2017-05-01T00:00:00Z") ] },
{ $lt: [ "$date", new Date("2018-03-16T00:00:00Z") ] },
{ $gte: [ { $hour: "$date" }, 15 ] },
{ $lt: [ { $hour: "$date" }, 17 ] }
]
},
then: "$$KEEP",
else: "$$PRUNE"
}
}
}
])