2015-11-12 54 views
0

我有一个MongoDB分析样式的集合。它包含带有timestamp字段和各种数据的文档。现在我想通过一个粒度参数来获得一段时间的文档数量。MongoDB聚合:具有粒度的时间序列

我目前使用这样的聚合框架(假设粒度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将取决于计算$dayOfMonth部分时使用的时区(每个count从00:00:000 UTC到UTC:23:59:999)。

我希望能够实现这一点,而不依赖于时区,但依靠start_time。例如,如果我在UTC时间07:00使用start_time,则我将在UTC时间07:00到第二天07:00 UTC的每一天获得count s。

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

关于如何执行此任何想法?

+0

不知道我明白你的意思取决于时间戳。 Mongo将所有日期存储为UTC,因此所有内容都位于同一时区。 –

+0

日期存储为UTC,因此如果使用$ dayOfMonth聚合运算符,则会获得UTC日期。现在,如果你想在不同的时区dayOfMonth,你不能。 更一般地说,我想获得24小时间隔的计数值(不依赖于任何时区,例如从昨天凌晨1:30到今天凌晨1:30)。 – Owumaro

回答

0

我发现了一个很好的解决方案。这不是很自然,但无论如何。

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

这里是一个例子,每天粒度:

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从原始时间戳中检索这些毫秒。

现在我可以用$dayOfMonth经营者本人的normalized_timestamp场拿到一天,如果我们考虑从13:30间隔13:30第二天,用$group获得计数值这些区间。

编辑:它来计算,以创建查询之前从时间戳移除正常化的价值更简单了,使用:

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

(每天粒度)

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