在匹配查询中返回每个$的X文档数量

时间:2016-08-02 23:34:57

标签: mongodb meteor mongodb-query aggregation-framework

我正在尝试通过匹配数组中的文档来查询集合,让我们调用Telemetry

var hardwareIDs = ['A','B','C'];
Telemetry.find({ hardwareID: { $in: hardwareIDs }});

以下是Telemetry记录的示例:

{
   _id: xxxx,
   insertedAtUTC: xxxx,
   hardwareID: xxxx,
   year: 2016,
   month: 2,
   day: 31,
   hour: 0,
   data: []
}

但我发现很难做到的是,让我们说,每个匹配查询的最新3个文档。因此,我有效地返回一个看起来类似于此的游标:

[
   { insertedAtUTC: 3, hardwareID: "A", ... },
   { insertedAtUTC: 2, hardwareID: "A", ... },
   { insertedAtUTC: 1, hardwareID: "A", ... },
   { insertedAtUTC: 3, hardwareID: "B", ... },
   { insertedAtUTC: 2, hardwareID: "B", ... },
   { insertedAtUTC: 1, hardwareID: "B", ... },
   { insertedAtUTC: 3, hardwareID: "C", ... },
   { insertedAtUTC: 2, hardwareID: "C", ... },
   { insertedAtUTC: 1, hardwareID: "C", ... }
]

有关如何制定MongoDB查询以解决此问题的任何想法?

我用meteor标记了这一点,因为我在MeteorJS中使用MongoDB。我目前正在尝试发布一个轻量级游标,因为Telemetry集合相当大,但我认为这不会对解决方案产生任何影响。

1 个答案:

答案 0 :(得分:1)

你可以通过使用mapreduce来实现:发出所有hardwareID而不是reduce,通过insertedAtUTC对它们进行排序。

此外,如果您想要更多地过滤字段的投影,您可以应用聚合,展开并对文档进行投影。 看看我的示例script.js:

use stackoverflow

db.dropDatabase()

db.telemetry.insert(
    [   
        { hardwareID: "C", insertedAtUTC: 2 },
        { hardwareID: "C", insertedAtUTC: 3 },
        { hardwareID: "C", insertedAtUTC: 1 },
        { hardwareID: "A", insertedAtUTC: 1 },
        { hardwareID: "A", insertedAtUTC: 2 },
        { hardwareID: "A", insertedAtUTC: 3 },
        { hardwareID: "B", insertedAtUTC: 3 },
        { hardwareID: "B", insertedAtUTC: 2 },
        { hardwareID: "B", insertedAtUTC: 1 },
        { hardwareID: "X", insertedAtUTC: 2 },
        { hardwareID: "X", insertedAtUTC: 1 }
    ]
)


var hardwareIDs = ['A','B','C'];

var map = function map(){
    emit(this.hardwareID, this);

};

var reduce = function(key, values){
    var sorted_values = values.sort(function(first, second) {
        return second.insertedAtUTC - first.insertedAtUTC;
    }).slice(0,2);
    return {key, sorted_values};
};


db.runCommand({"mapReduce":"telemetry", map:map, reduce:reduce, out:{replace:"telemetry2"}, query:{ hardwareID: { $in: hardwareIDs }}})

var result = db.telemetry2.aggregate(
    [
     { $unwind : {path: '$value.sorted_values' }},
     { $project: {
        _id: '$value.sorted_values._id',
        hardwareID: '$value.sorted_values.hardwareID',
        insertedAtUTC: '$value.sorted_values.insertedAtUTC'
        } 
     }
    ]
);

while(result.hasNext()){
    printjson(result.next());
}

您可以通过

在控制台中运行脚本
mongo < script.js