代码之家  ›  专栏  ›  技术社区  ›  Baklap4

MongoDB聚合AVG()

  •  1
  • Baklap4  · 技术社区  · 8 年前

    嘿,伙计们,如果涉及到聚合,我真的是一个新手,所以请帮助我解决这个问题。

    假设我有多个文档(随着时间推移),如下所示:

    {
      "_id": ObjectId("574d6175da461e77030041b7"),
      "hostname": "VPS",
      "timestamp": NumberLong(1460040691),
      "cpuCores": NumberLong(2),
      "cpuList": [
        {
          "name": "cpu1",
          "load": 3.4
        },
        {
          "name": "cpu2",
          "load": 0.7
        }
      ]
    },
    {
      "_id": ObjectId("574d6175da461e77030041b7"),
      "hostname": "VPS",
      "timestamp": NumberLong(1460040700),
      "cpuCores": NumberLong(2),
      "cpuList": [
        {
          "name": "cpu1",
          "load": 0.4
        },
        {
          "name": "cpu2",
          "load": 6.7
        }
      ]
    },
    {
      "_id": ObjectId("574d6175da461e77030041b7"),
      "hostname": "VPS",
      "timestamp": NumberLong(1460041000),
      "cpuCores": NumberLong(2),
      "cpuList": [
        {
          "name": "cpu1",
          "load": 25.4
        },
        {
          "name": "cpu2",
          "load": 1.7
        }
      ]
    }
    

    我想得到X时间内的平均cpu负载。其中X等于300秒。

    因此,通过上面的示例,可以得到如下结果集:

    {
        "avgCPULoad": "2.8",
        "timestamp": NumberLong(1460040700)
    },
    {
        "avgCPULoad": "13.55",
        "timestamp": NumberLong(1460041000)
    }
    

    avgCpuLoad的计算如下:

    1. 在300秒内抓取所有文档
    2. 计算平均值:
      1. (((3.4+0.7)/2)+((0.4+6.7)/2))/2 = 2.8
      2. ((25.4+1.7)/2) = 13.55
    3. 从所选文档中添加上次时间戳。

    我知道我每次都会得到每个文件。这样做:

    db.Pizza.aggregate(
    [
        {
            $group: 
            {
                _id:
                {
                    $subtract: [
                        '$timestamp',   
                        {
                            $mod: ['$timestamp', 300]
                        }
                    ]
                },
                'timestamp': {$last:'$timestamp'}
            },
        {
            $project: {_id: 0, timestamp:'$timestamp'}
        }
    ])
    

    但是怎样才能得到上面计算的平均值呢? 我试过一点 $unwind 但没有给出我想要的结果。。

    2 回复  |  直到 7 年前
        1
  •  1
  •   chridam Gino Claudi    8 年前

    您需要运行以下聚合操作才能获得所需的结果:

    db.collection.aggregate([ 
        { "$unwind": "$cpuList" },
        {
            "$group": {
                "_id": {                
                    "interval": {
                        "$subtract": [ 
                            "$timestamp",                        
                            { "$mod": [ "$timestamp", 60 * 5 ] }
                        ]
                    }
                },             
                "avgCPULoad": { "$avg": "$cpuList.load" },
                "timestamp": { "$max": "$timestamp" }
            } 
        },
        {
            "$project": { "_id": 0, "avgCPULoad": 1, "timestamp": 1 }
        }
    ])
    

    以上按5分钟间隔(以秒为单位)对扁平文档进行分组;当实际时间戳除以5分钟间隔(以秒为单位)时,从得到的余数中减去时间戳(以秒计),就得到了时间间隔键

    示例输出

    /* 1 */
    {
        "avgCPULoad" : 13.55,
        "timestamp" : NumberLong(1460041000)
    }
    
    /* 2 */
    {
        "avgCPULoad" : 2.8,
        "timestamp" : NumberLong(1460040700)
    }
    
        2
  •  1
  •   Jan Doornbos    8 年前

    解决方法是在数组上使用解卷(cpulist)。我为您做了一个示例查询:

    db.CpuInfo.aggregate([
        {
            $unwind: '$cpuList'
        },
        {
            $group: {
                _id:{
                    $subtract:[
                        '$timestamp', 
                        {$mod: ['$timestamp', 300]}
                    ]
                }, 
                'timestamp':{$last:'$timestamp'},
                'cpuList':{$avg:'$cpuList.load'}
            }
        }
    ])