mongodb按时间间隔10分钟聚合时间戳

时间:2015-05-28 17:53:32

标签: mongodb aggregation-framework

我尝试将与查询匹配的大型数据集分组为10分钟"时间片"。我想知道是否有办法有效地使用mongodb的聚合函数。

我有一个看起来像的文件:

{
    _id: ObjectID(""),
    groupID: '1234',
    name: 'dataPointName',
    timestamp: 1432765200000,
    value: 1234
}

然后,我想在名为"grouped_data"的10分钟组间隔中对[时间戳,值]对的数组进行分组。我想知道是否有一种有效的方法来执行所有这些操作?

2 个答案:

答案 0 :(得分:5)

您可以先投射一个新的日期字段,然后按间隔进行分组。

假设您有以下测试文档:

db.collection.insert([
    {
        groupID: '1234',
        name: 'dataPointName',
        timestamp: 1432765200000,
        value: 1234
    },
    {
        groupID: '1234',
        name: 'dataPointName',
        timestamp: 1432765300000,
        value: 1234
    },
    {
        groupID: '1234',
        name: 'dataPointName',
        timestamp: 1432766100000,
        value: 1234
    }
])

然后,您可以实施以下聚合:

db.collection.aggregate([
    {
        "$project": {
            "date": { "$add": [new Date(0), "$timestamp"] },
            "timestamp": 1,
            "value": 1
        }
    },
    { 
        "$group": {
            "_id": {
                "year": { "$year": "$date" },
                "dayOfYear": { "$dayOfYear": "$date" },
                "interval": {
                    "$subtract": [ 
                        { "$minute": "$date" },
                        { "$mod": [{ "$minute": "$date"}, 10 ] }
                    ]
                }
            },
            "grouped_data": { "$push": {"timestamp": "$timestamp", "value": "$value" } }
        }
    },
    {
        "$project":{
            "_id": 0,
            "grouped_data": 1
        }
    }
])

<强>输出

/* 0 */
{
    "result" : [ 
        {
            "grouped_data" : [ 
                {
                    "timestamp" : 1432766100000,
                    "value" : 1234
                }
            ]
        }, 
        {
            "grouped_data" : [ 
                {
                    "timestamp" : 1432765200000,
                    "value" : 1234
                }, 
                {
                    "timestamp" : 1432765300000,
                    "value" : 1234
                }
            ]
        }
    ],
    "ok" : 1
}

- 编辑 -

要将数据格式化为[timestamp,value]而不是键/值数组,可以使用聚合游标的forEach()方法,如下所示:

var result = [];   
db.collection.aggregate(pipeline).forEach(function (doc){    
    data = []; 
    doc.grouped_data.forEach(function (obj){               
        data.push(obj.timestamp);
        data.push(obj.value);        
    });
    result.push(data);
})

printjson(result);

<强>输出

[
        [
                1432766100000,
                1234
        ],
        [
                1432765200000,
                1234,
                1432765300000,
                1234
        ]
]

答案 1 :(得分:1)

这显然是一个可以使用map-reduce轻松解决的问题。此处的密钥将timestamp / (10*60*1000)舍入到最大的较低整数。而且您只需要在缩减步骤中汇总grouped_data

然而,这有点复杂,因为我假设您需要保留按时间戳排序的值(请记住reduce function should be commutative)。为了提供帮助,我将使用终结器对结果进行排序。

map = function() {
  window_width = 10*60*1000
  emit(Math.floor(this.timestamp/window_width),
       { grouped_data: [[ this.timestamp, this.value]] })
}

// aggregates values by concatenating the [[timestamp, values]] arrays
// don't bother sorting here as this will be done by the finalizer
reduce = function(key, values) {
  return values.reduce(
            function(a,b) { return { grouped_data: a.grouped_data.concat(b.grouped_data)} }
      )
} 

// Sort data in each array by timestamp
finalize = function(key, reducedValue) {
  return { grouped_data: reducedValue.grouped_data.sort(function(a,b) { a[0] - b[0] }) }
}

制作(使用一些虚拟数据集):

> db.w.mapReduce(map, reduce, { finalize: finalize, out: {inline:1}}).results
[
    {
        "_id" : 2387925,
        "value" : {
            "grouped_data" : [
                [
                    1432755300001,
                    1234
                ],
                [
                    1432755300000,
                    1234
                ]
            ]
        }
    },
    {
        "_id" : 2387942,
        "value" : {
            "grouped_data" : [
                [
                    1432765200000,
                    1234
                ],
                [
                    1432765200001,
                    1234
                ],
                [
                    1432765300000,
                    1234
                ],
                [
                    1432765300001,
                    1234
                ]
            ]
        }
    }
]