在MongoDB中存储和查询时间间隔

时间:2015-02-12 15:42:47

标签: mongodb mongodb-query

建模班次规划应用程序:

我提出了描述shift

的数据结构
{
    "fromHour" : 7,
    "fromMinute" : 30,
    "toHour" : 9,
    "toMinute" : 30,
    "week" : 5,
    "date" : "2015-01-26",
    "user" : {
       // ...
    },
    "_id" : ObjectId("54d0e4a82b9dc26c0c0f36e7")
}

我需要存储的主要信息是: 1.当班次开始时(小时和分钟), 2.换班结束时(小时和分钟)和 它实际发生的日期。

字段fromHourfromMinutetoHourtoMinutedate作为ISO字符串对我来说非常适合存储和查询特定的班次日期。

当我需要从中构建报告时,问题就出现了。说,我希望从07:00到23:00之间的所有班次从“2015-01-01”到“2015-02-01”。

我可以在查询中添加$and子句,例如

[ { fromHour: { '$gte': 7 } },
  { fromMinute: { '$gte': 0 } },
  { toHour: { '$lt': 23 } },
  { toMinute: { '$lt': 0 } } ]

但是这样做效果不好,因为在toMinute转换为$lt时,{{1}}将为假。

我正在努力寻找能够存储易于查询的时间跨度的高效数据结构。

2 个答案:

答案 0 :(得分:2)

在两个不同的字段中存储小时和分钟太容易出错,这使您的工作更加困难。由于Mongo没有明显的" Time"数据类型,只有日期,并且班次通常在" easy"开始和结束。有些时候,我建议实现类似的方法,例如将时间转换为应用程序中的实数:

00:00 --> 0
01:00 --> 1
...
08:00 --> 8
08:15 --> 8.25
08:30 --> 8.5
...
16:30 --> 16.5
...

在应用程序中有一些额外的工作,因为您必须在保存或显示时进行转换,但它仍然比在两个不同的字段中具有单个时间值更好。

所以你的数据看起来像这样:

{
    "shiftStart" : 7.5,
    "shiftEnd" : 9.5,
    "week" : 5,
    "date" : "2015-01-26",
    "user" : {
       // ...
    },
    "_id" : ObjectId("54d0e4a82b9dc26c0c0f36e7")
}

和您的查询:

[ { shiftStart: { '$gte': 7 } },
  { shiftEnd: { '$lt': 23 } } ]

答案 1 :(得分:1)

您可以使用ISODate(...)格式存储日期类型的数据,然后使用$projectDate Aggregation Operators查询数据。

对于你的例子:

db.shifts.aggregate([
  { $match:  //matches the dates first to filter out before $project step
    { datetimeStart:
      { $gte: ISODate("2015-01-01T07:00:00.000Z"),
        $lt: ISODate("2015-02-01T00:00:00.000Z")
      },
      datetimeEnd:
      { $gte: ISODate("2015-01-01T07:00:00.000Z"),
        $lt: ISODate("2015-02-01T00:00:00.000Z")
      }
    }
  },
  { $project:  // $project step extracts the hours
    { otherNeededFields: 1,  // any other fields you want to see
      datetimeStart: 1,
      datetimeEnd: 1,
      hourStart: { $hour: "$datetimeStart" },
      hourEnd: { $hour: "$datetimeEnd" }
    }
  },
  { $match: // match the shift hours
    { hourStart: { $gte: 7 },
      hourEnd: { $lte: 23 }
    }
  }
])

使用此系统可能可能,但复杂可在上午7:30至晚上10:30之间找到更多类似的内容:

db.shifts.aggregate([
  { $match:  //matches the dates first to filter out before $project step
    { datetimeStart:
      { $gte: ISODate("2015-01-01T07:30:00.000Z"),
        $lt: ISODate("2015-02-01T00:00:00.000Z")
      },
      datetimeEnd:
      { $gte: ISODate("2015-01-01T07:30:00.000Z"),
        $lt: ISODate("2015-02-01T00:00:00.000Z")
      }
    }
  },
  { $project:  // $project step extracts the hours
    { otherNeededFields: 1,  // any other fields you want to see
      datetimeStart: 1,
      datetimeEnd: 1,
      hourStart: { $hour: "$datetimeStart" },
      minStart: { $minute: "$datetimeStart" },
      hourEnd: { $hour: "$datetimeEnd" },
      minEnd: { $minute: "$date
    }
  },
  { $match: // match the shift hours
    { $or:
      [
        {hourStart: 7, minStart: {$gte: 30}}, // hour is 7, minute >= 30
        {hourStart: { $gte: 8 }}  // hour is >= 8
      ],
      $or:
      [
        {hourEnd: 22, minEnd: {$lte: 30}}, // hour is 22, minute <= 30
        {hourEnd: { $lte: 21 }} // hour is <= 21
      ]
    }
  }
])