在Mongo中,如何在Date对象上根据时间将搜索查询写入搜索文档。

时间:2017-11-08 06:10:11

标签: mongodb mongodb-query aggregation-framework

我们有一个名为Incident的Collection。其中我们有一个字段StartTime(Date对象类型)。 每天,只要满足事件条件,就会创建新的文档条目并将其插入到集合中。 我们必须得到所有事件,这些事件发生在晚上10点到早上6点之间。 (即从午夜到清晨)。

但是我面临着如何为这个用例编写查询的问题。 由于我们有日期对象,我可以在两个日期之间编写查询到搜索文档。 如何在Date对象上基于时间编写搜索查询。 样本数据:

"StartTime" : ISODate("2015-10-16T18:15:14.211Z")

1 个答案:

答案 0 :(得分:1)

这不是一个好主意。但基本上你应用日期聚合运算符:

db.collection.aggregate([
  { "$redact": {
    "$cond": {
      "if": {
        "$or": [
          { "$gte": [{ "$hour": "$StartTime" }, 22] },
          { "$lt": [{ "$hour": "$StartTime" }, 6 ] }
        ]
      },
      "then": "$$KEEP",
      "else": "$$PRUNE"
    }
  }}
])

使用$redact仅返回或$$KEEP符合Date提取的$hour$$PRUNE或&#的两种条件的文档34;删除"从结果那些没有。

与MongoDB 3.6及其后续版本相比有点短,但实际上并没有什么不同:

db.collection.find({
  "$expr": {
    "$or": [
      { "$gte": [{ "$hour": "$StartTime" }, 22] },
      { "$lt": [{ "$hour": "$StartTime" }, 6 ] }
    ]
  }
})

总的来说,这不是一个好主意,因为该语句需要扫描整个集合并计算该逻辑条件。

更好的方法是实际存储" "时间"作为一个单独的领域:

var ops = [];

db.collection.find().forEach(doc => {
  // Get milliseconds from start of day
  let timeMillis = doc.StartTime.valueOf() % (1000 * 60 * 60 * 24);

  ops.push({
    "updateOne": {
      "filter": { "_id": doc._id },
      "update": { "$set": { timeMillis } }
    }
  });

  if ( ops.length > 1000 )  {
    db.collection.bulkWrite(ops);
    ops = [];
  }
})

if ( ops.length > 0 )  {
  db.collection.bulkWrite(ops);
  ops = [];
}

然后你可以简单地查询:

var start = 22 * ( 1000 * 60 * 60 ),   // 10PM
    end = 6 * ( 1000 * 60 * 60 );      // 6AM

db.collection.find({ 
  "$or": [
    { "timeMillis": { "$gte": start } },
    { "timeMillis": { "$lt": end } }
  ]
);

该字段实际上可以编入索引,从而快速有效地返回结果。