MongoDB聚合方面在日期范围内以天为单位

时间:2017-04-24 21:11:50

标签: mongodb aggregation-framework

如何在MongoDB 3.4.1中使用两个字段来填充该范围涵盖的日期范围内的文档?

例如,我有以下文件:

{ start: ISODate('2017-04-01T12:30:00Z'), end: ISODate('2017-04-02T12:30:00Z') },
{ start: ISODate('2017-04-04T12:00:00Z'), end: ISODate('2017-04-04T12:30:00Z') },
{ start: ISODate('2017-04-04T12:30:00Z'), end: ISODate('2017-04-08T12:30:00Z') },
{ start: ISODate('2017-04-05T12:30:00Z'), end: ISODate('2017-04-06T12:30:00Z') },
{ start: ISODate('2017-04-08T12:30:00Z'), end: ISODate('2017-04-09T12:30:00Z') }

我希望将这些内容添加到以下直方图中:

[
  { '2017-04-01': 1 },
  { '2017-04-02': 1 },
  { '2017-04-04': 2 },
  { '2017-04-05': 2 },
  { '2017-04-06': 2 },
  { '2017-04-07': 1 },
  { '2017-04-08': 2 },
  { '2017-04-09': 1 }
]

如果文档的日期范围涵盖一天中的任何部分,则该文档应该计入当天的1个项目。

如果可能,我想使用单个汇聚管道执行此分段。通过使用日期格式化程序(例如:

)将它们投影到单个时间戳字段,这非常简单
{ $project: { day: { $dateToString: { format: '%Y-%m-%d', date: '$start' } } } }

但似乎没有那些聚合运算符支持日期范围。

1 个答案:

答案 0 :(得分:2)

不是很简单,但这很有效。如果您需要精确的输出格式,则需要在3.4.4中引入新的$objectToArray表达式。

编辑:这不考虑闰年,因为它假定每年有365天。

const millisPerDay = 1000 * 60 * 60 * 24;

var results = db.dates.aggregate([
    {
      $project: {
          start: 1,
          range: {
              $range: [
                  0,
                  {
                    $add: [
                        1,
                        {
                          $add: [
                              {$multiply: [365, {$subtract: [{$year: "$end"}, {$year: "$start"}]}]},
                              {$subtract: [{$dayOfYear: "$end"}, {$dayOfYear: "$start"}]}
                          ]
                        }
                    ]
                  }
              ]
          }
      }
    },
    {
      $project: {
          daysOfEvent: {
              $map: {
                  input: "$range",
                  in : {$add: ["$start", {$multiply: ["$$this", millisPerDay]}]}
              }
          }
      }
    },
    {$unwind: "$daysOfEvent"},
    {$group: {_id: {$dateToString: {format: '%Y-%m-%d', date: "$daysOfEvent"}}, count: {$sum: 1}}},
    {$sort: {_id: -1}},
    {$replaceRoot: {newRoot: {$arrayToObject: [[{k: "$_id", v: "$count"}]]}}}
]);