我尝试将与查询匹配的大型数据集分组为10分钟"时间片"。我想知道是否有办法有效地使用mongodb的聚合函数。
我有一个看起来像的文件:
{
_id: ObjectID(""),
groupID: '1234',
name: 'dataPointName',
timestamp: 1432765200000,
value: 1234
}
然后,我想在名为"grouped_data"
的10分钟组间隔中对[时间戳,值]对的数组进行分组。我想知道是否有一种有效的方法来执行所有这些操作?
答案 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
]
]
}
}
]