MongoDB聚合:粒度为

时间:2015-11-12 15:48:45

标签: mongodb aggregation-framework

我有一个MongoDB Analytics风格的集合。它包含具有timestamp字段和各种数据的文档。现在我想得到一个时间序列,其中包含一个具有粒度参数的时间段的文档数。

我目前正在使用这样的聚合框架(假设粒度为DAY):

db.collection.aggregate([{
  $match: {
    timestamp: {
      $gte: start_time,
      $lt: end_time
    }
  }
}, {
  $group: {
    _id: {
      year: { $year: '$timestamp' },
      month: { $month: '$timestamp' },
      day: { $dayOfMonth: '$timestamp' }
    },
    count: { $sum: 1 }
  }
}, {
  $sort: {
    _id: 1
  }
}])

这样我每天都有count值。 问题是count s将取决于计算$dayOfMonth部分时使用的时区(每个count从00:00:000 UTC到23:59:999 UTC)。

我希望能够在不依赖时区的情况下实现这一目标,而是依赖于start_time。 例如,如果我在UTC时间07:00使用start_time,我会在每天07:00 UTC到第二天07:00 UTC获得count秒。

TL; DR:我想要这样的内容:https://dev.twitter.com/ads/reference/get/stats/accounts/%3Aaccount_id/campaigns

有关如何执行此操作的任何想法?

1 个答案:

答案 0 :(得分:0)

我找到了一个非常好的解决方案。不管怎样,这不是很自然。

这个想法是根据startDate和行的日期计算“标准化”日期。我在startDate上使用$mod运算符来获取毫秒+秒+小时(在DAY粒度的情况下),然后我使用$subtract从行的日期中减去它。 / p>

以下是DAY粒度的示例:

var startDate = ISODate("2015-08-25 13:30:00.000Z")
var endDate   = ISODate("2015-08-27 13:30:00.000Z")

db.collection.aggregate([{
    $match: {
      timestamp: {
        $gte: startDate,
        $lt: endDate
    }
}, {
  $project: {
    timestamp_normalized: {
      $subtract: [
        "$timestamp",
        {
          $mod: [
            { "$subtract": [ startDate, new Date("1970-01-01") ] },
            1000 * 60 * 60 * 24
          ]
        }
      ]
    }
  }
}, {
  // now $group with $dayOfMonth
}])

$mod部分计算00:00 UTC之后startDate的小时+秒+毫秒数,以毫秒为单位。

$subtract从原始时间戳中检索这些毫秒。

现在,如果我们考虑第二天的13:30到13:30之间的时间间隔,我可以在$dayOfMonth字段上使用normalized_timestamp运算符来获取当天,并使用$group获取计算这些间隔的值。

编辑:使用以下方法计算要在创建查询之前从标准化时间戳中删除的值更加容易:

(startDate - new Date(0)) % (1000 * 60 * 60 * 24)

(对于DAY粒度)

然后直接从timestamp中减去此值,而不是使用$mod