如何在Mongo中独立过滤日期和时间?

时间:2018-05-01 14:35:47

标签: mongodb mongoose mongodb-query aggregation-framework

如何在Mongo中独立地按日期和时间进行过滤?

我希望能够在数据库中独立保存和日期,我可以按日期和时间独立地过滤。

我是否只有一个保存日期对象的字段?如果是,我怎么能按时间过滤。我如何获得有关记录的统计数据,例如日期为2017年5月1日至15/03/2018 AND 记录的时间应介于下午3点至5点(所以记录日期为12/03/2018,下午5:05的时间不应包括在内。

2 个答案:

答案 0 :(得分:2)

这里要考虑的重要一点是,你实际上需要继续在这里使用"regular query operators",否则你的性能会大幅下降。我们的想法是始终编写一个实际上可以“使用索引”的查询,然后确保您的索引存在。

因此,“天”的选择是一个标准范围查询,剩下的只是回到过滤带有“计算”的表达式,考虑到“已经选择”的文件正确指定标准查询条件第一次

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 operatorsdate operatorsRegular comparison operators表示日期范围。

较低版本 - Aggregate和$ 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管道阶段应用。日期范围表达式Regular comparison operators$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}`
})

$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"            
            }
        } 
    }
])