【问题标题】:Group by Timestamp with aggregation framework in MongoDB使用 MongoDB 中的聚合框架按时间戳分组
【发布时间】:2014-07-08 23:06:27
【问题描述】:

我的 MongoDB 查询中有以下对象数组,以获取一些基于时间的统计信息:

[
    { 
        _id: { year: 2014, dayOfYear: 128, hour: 9 },
        count: 2,
        avg: 0.12455,
        min: 0.1245,
        max: 0.1246, 
        gv: 7.98954654895666, 
        bv: 0.9950000000000001 
    },
    { 
        _id: { year: 2014, dayOfYear: 134, hour: 14 },
        count: 8,
        avg: 0.12217854,
        min: 0.1212,
        max: 0.12345678,
        gv: 25.869999999999997,
        bv: 3.1652450614477337
    },
    { 
        _id: { year: 2014, dayOfYear:126, hour: 19 },
        count: 3,
        avg: 0.11234099999999998,
        min: 0.112341,
        max: 0.112341,
        gv: 29.849999999999998,
        bv: 3.3533788500000004
    }
]

我想基本上将 _id 对象转换为带有 moment.js 的 unix 时间戳我只是找不到正确的下划线函数来遍历对象,获取 ID 数据并再次从中创建一个数组。

在这个过程中我可以做 moment().year('2014').format('Z')

想要的结果:

{
    unixtime: 1400599394,
    count: 3,
    avg: 0.11234099999999998,
    min: 0.112341,
    max: 0.112341,
    gv: 29.849999999999998,
    bv: 3.3533788500000004
}

【问题讨论】:

  • 这实际上是聚合框架的输出吗?如果是这样,你的真正目的是什么?您只想在每天的“小时”内分组吗?

标签: javascript mongodb underscore.js momentjs aggregation-framework


【解决方案1】:

我知道您确实询问过如何使用 Promise 执行此操作,但我只是根据_id 下字段的命名在这里进行测试,这实际上是从aggregation framework 输出的,因此存在是另一种方法。

您似乎使用过的date operators 非常适合它们的用途,但由于您似乎想要一个 unix 时间戳作为输出,那么合乎逻辑的做法是将该字段保持为 unix 时间戳格式,仅使用分组你需要的界限。

这似乎是在每天对“每小时”进行分组,所以让我们应用日期数学来更改时间戳值。因此,不要使用日期运算符来分解 $group 管道键中的日期,而是这样做:

{ "$group": {
    "_id": {
        "$subtract": [ 
            { "$subtract": [ "$created", new Date("1970-01-01") ] },
            { "$mod": [ 
                { "$subtract": [ "$created", new Date("1970-01-01") ] },
                1000*60*60 
            ]}
        ]
    }
}}

当然包括您在聚合管道中拥有的所有其他内容(此问题中未提供),但结果是将实际纪元时间戳值从您的原始日期字段截断为一天中的小时,即命名为“创建”。

只是为了分解这部分,考虑这个日期对象:

var date = new Date()
date.valueOf()
1400639001169

因此,您可以看到从日期对象中提取的纪元时间戳表示。在数学方面,通过.valueOf() 方法检索该值与以下内容完全相同:

date - new Date("1970-01-01")
1400639001169

它为您提供自“1970-01-01”以来经过的秒数(在本例中为毫秒),这正是纪元时间。为了进一步做到这一点,我们可以通过获取模数来获取 1 小时内经过的毫秒数作为该日期的一部分:

date % ( 1000*60*60 )
1401169

因此,以一秒为 1000 毫秒、一分钟为 60 秒、一小时为 60 分钟,我们得到了这个结果。现在剩下的就是从原始日期值中减去该值:

date - date % ( 1000*60*60 )
1400637600000

该值现在是一天中小时的边界,适合分组,也是您想要的输出结果。仅供参考,以下是初始时间戳和转换时间戳的字符串格式值:

初始时间:格林威治标准时间 2014 年 5 月 21 日星期三 02:23:21 转换时间:格林威治标准时间 2014 年 5 月 21 日星期三 02:00:00

因此,基本上,您对使用 date operators 的分组执行相同的操作,但实际上无需额外转换即可获得所需的输出格式。

只是一个很酷的技巧,如果我对你如何到达这里的方式正确,那么应该对你有用,如果不是,那么至少应该对可能以这种方式到达这里的其他人有用。

【讨论】:

  • 你先生,真是个天才!!是的,我已经将它与聚合进行了分组,这非常简单。我找不到合适的方法来制作“hourdayyears 等”。回到时间戳..我检查了答案,它完美无缺。似乎比使用所有 javascript 变通办法更好。谢谢你,尼尔。
  • @xanatas 没问题,就像我说的,看起来这就是你在做的事情。 Pitty 您的问题的标题和措辞都指向 JavaScript 解决方案。介意我在那里做一些编辑吗?
猜你喜欢
  • 1970-01-01
  • 2013-07-31
  • 2013-03-19
  • 2020-01-12
  • 1970-01-01
  • 1970-01-01
  • 2021-04-29
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多