【问题标题】:Storing and querying time intervals in MongoDB在 MongoDB 中存储和查询时间间隔
【发布时间】:2015-04-13 10:28:14
【问题描述】:

建模班次计划应用程序:

我想出了这样的数据结构来描述shift

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

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

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 是 30 的班次,$lt 将是错误的。

我正在尝试找到有效的数据结构,以允许存储易于查询的时间跨度。

【问题讨论】:

    标签: mongodb mongodb-query


    【解决方案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
          ]
        }
      }
    ])
    

    【讨论】:

    • 这只是一个很好的答案。确实,案例 7:30 / 22:30 是真实的。然而,解决方案的复杂性使其吸引力降低。如果在那里发现问题,我将尝试@Laszlo Tenki 的解决方案,我会回到这里。
    【解决方案2】:

    将小时和分钟分别存储在两个不同的字段中太容易出错,并且会使您的工作更加困难。由于 Mongo 没有独特的“时间”数据类型,只有日期,并且班次通常在“轻松”时间开始和结束,我建议在您的应用程序中实现类似将时间转换为实数的方法,如下所示:

    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 } } ]
    

    【讨论】:

    • 我实际上正在考虑类似的事情,但不确定这是否是个好主意.. 非常感谢您的建议。
    • 如果你决定采用这个解决方案,一个相当简单的系统来获取你想要输入的数字是:( ( Date.UTC(&lt;year&gt;,&lt;month&gt;,&lt;day&gt;,&lt;hour&gt;,&lt;min&gt;,&lt;sec&gt;) / 1000 ) % 86400 ) / 3600。这应该得到 UNIX 时间戳 mod 一天中的秒数,然后除以一小时内的秒数。
    • @NoOutlet 似乎是,最简单的是fromHour + fromMinute / 60.0
    猜你喜欢
    • 2021-06-17
    • 2016-11-11
    • 1970-01-01
    • 2023-02-21
    • 2019-09-11
    • 2011-09-20
    • 2020-02-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多