【问题标题】:MongoDB aggregation : time series with granularityMongoDB聚合:具有粒度的时间序列
【发布时间】:2015-11-26 00:06:30
【问题描述】:

我有一个 MongoDB 分析风格的集合。它包含带有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 值。 问题是 counts 将取决于计算 $dayOfMonth 部分时使用的时区(每个 count 是从 00:00:000 UTC 到 23:59:999 UTC)。

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

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

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

【问题讨论】:

  • 不确定我是否理解您的意思,具体取决于时间戳。 Mongo 将所有日期存储为 UTC,因此所有内容都在同一个时区。
  • 日期存储为 UTC,因此如果您使用 $dayOfMonth 聚合运算符,您将获得 UTC 日期。现在,如果您希望 dayOfMonth 在不同的时区,则不能。更一般地说,我想获取 24 小时间隔的计数值(不依赖于任何时区,例如从昨天凌晨 1:30 到今天凌晨 1:30)。

标签: mongodb aggregation-framework


【解决方案1】:

我找到了一个效果很好的解决方案。这不是很自然,但无论如何。

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

以下是 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 的时间间隔,现在我可以在 normalized_timestamp 字段上使用 $dayOfMonth 运算符来获取日期,并使用 $group 获取这些时间间隔的计数值。

编辑:在创建查询之前计算要从时间戳中删除以进行规范化的值甚至更容易,使用:

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

(对于 DAY 粒度)

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

【讨论】:

    猜你喜欢
    • 2015-10-11
    • 2023-03-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-11
    • 2020-03-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多