首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >MongoDB按时间间隔聚合

MongoDB按时间间隔聚合
EN

Stack Overflow用户
提问于 2014-06-07 20:27:08
回答 1查看 1.6K关注 0票数 0

我使用MongoDB存储每15秒捕获一次的服务器统计信息(因此每个服务器每分钟插入4行),并试图将这些数据绘制到某个时间戳之间的所有数据的图表上。

例如,可以使用以下查询:

代码语言:javascript
运行
复制
$tbl->find(
  array(
    "timestamp" => array('$gte' => '1396310400', '$lte' => '1396915200'), 
    "service" => 'a715feac3db42f54edbc50ef6fa057b3'
  ),
  array("timestamp" => 1, "system" => 1)
);

它吐出了一堆像这样的行:

代码语言:javascript
运行
复制
Array
(
    [53933ad8532965621d97dd3b] => Array
        (
            [_id] => MongoId Object
                (
                    [$id] => 53933ad8532965621d97dd3b
                )

            [system] => Array
                (
                    [load] => 0.55
                    [uptime] => 1171204.47
                    [processes] => 222
                )

            [timestamp] => 1396310403
        )

)

这对于小数据范围很好,因为我可以将这些数据直接传递到Flot或HighCharts中,让它自己美化时间尺度。然而,这并不适用于大型数据集(例如,查询超过一个月)。

我要做的是按小时(或15分钟)对数据进行分组,并返回给定时间段的平均值(在本例中,它是我正在绘制的system.load )。

我知道聚合函数是我需要使用的,但是尽管我尽了最大的努力,我还是无法做到这一点。

现在,我让PHP完成所有的工作(按时间戳将结果分组并计算出平均值),但是它非常慢,而且我知道MongoDB会更好地处理它。

任何洞察力都将不胜感激!

编辑:我一直在努力跟踪这里发布的答案,但仍在挣扎-- MongoDB聚合PHP,按小时分组

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2014-06-08 00:41:32

我正在查看您在问题顶部的初始查询,它立即告诉我,您的“时间戳”值实际上是字符串。因此,毫无疑问,当您阅读这些信息并进行“手动聚合”时,您实际上是将这些值以及可能的其他值转换为您可以操作的类型、求和和平均值。

因此,这里的第一部分是修复您的数据,看起来它来自日志源,但是您从未转换过这些值。我认为这有可能不仅是时间戳值,而且可能也是系统下的度量标准。

这使您可以选择如何存储时间戳。您可以保留它作为时间戳号,因为它目前是字符串形式,或者您可以选择转换为BSON日期类型。第一个是简单的整数转换并保存回存,另一个则应该能够输入驱动程序支持的Date类型,然后再次保存数据。

这样做之后,您就可以愉快地使用聚合函数了。因此,举个例子,如果您选择将它保持为一个数字,那么您只需应用日期数学来获得分组边界:

代码语言:javascript
运行
复制
db.collection.aggregate([

   // Match documents on the range you want
   { "$match": {
       "timestamp": {
           "$gte": 1396310400, "$lte": 1396915200
       },
       "service": "a715feac3db42f54edbc50ef6fa057b3"
   }},

   // Group on the time intervals, 15 minutes here
   { "$group": {
       "_id": { 
           "service": "$service",
           "time": {
               "$subtract": [
                   "$timestamp",
                   { "$mod": [ "$timestamp", 60 * 15 ] }
               ]
           }
       },
       "load": { "$avg": "$system.load" }
   }},

   // Project to the output form you want
   { "$project": {      
       "service": "$_id.service",
       "time" : "$_id.time",
       "load": 1
   }}
])

或者是php特定的

代码语言:javascript
运行
复制
$tbl->aggregate(array(
    array(      
        '$match' => array(
            'timestamp' => array(
                '$gte' => 1396310400, '$lte' => 1396915200
            ),
            'service' => 'a715feac3db42f54edbc50ef6fa057b3'
        )
    ),
    array(
        '$group' => array(
            '_id' => array(
                'service' => '$service',
                'time' => array(
                    '$subtract' => array(
                       '$timestamp',
                       array( '$mod' => array('$timestamp', 60 * 15 ) )
                    )
                )
            ),
            'load' => array( '$avg' => '$system.load' )
        )
    ),
    array(
        '$project' => array(
            'service' => '$_id.service',
            'time' => '$_id.time',
            'load' => 1
        )
    )
))

否则,如果选择转换为BSON日期,则可以使用日期聚合运算符

代码语言:javascript
运行
复制
db.collection.aggregate([
   { "$match": {
       "timestamp": {
           "$gte": new Date("2014-04-01"), "$lte": new Date("2014-04-08")
       },
       "service": "a715feac3db42f54edbc50ef6fa057b3"
   }},
   { "$group": {
       "service": "$service",
       "time": {
           "dayOfYear": { "$dayOfYear": "$timestamp" },
           "hour": { "$hour": "$timestamp" },
           "minute": {
               "$subtract": [
                   { "$minute": "$timestamp" },
                   { 
                       "$mod": [
                           { "$minute": "$timestamp" },
                           15
                       ]
                   }
               ]
           }
       },
       "load": { "$avg": "$system.load" }
   }},
   { "$project": {
       "service": "$_id.service",
       "time": "$_id.time",
       "load": 1
   }}
])

因此,您可以在日期聚合运算符的帮助下分解日期的某些部分,并且仍然使用相同的模块操作来获得间隔值。

如果您仍然喜欢日期数学方法,您仍然可以使用date对象来实现这一点,因为从另一个日期对象中减去一个日期对象的结果将是划时代的时间戳值。因此,将BSON日期转换为一个划时代的时间戳只是一个问题:

代码语言:javascript
运行
复制
{
    "$subtract": [
        "$dateObjectField",
        new Date("1970-01-01")
    ]
}

因此,在这里传递给管道的任何“日期”值都可以使用驱动程序的本机类型方法进行强制转换,并且在将请求发送到MongoDB时将正确序列化。另一个优点是,当您将它们读回时,情况也是一样的,因此在客户端处理中不再需要转换。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/24101286

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档