【问题标题】:Return X amount of documents for each $in matching query为每个 $in 匹配查询返回 X 数量的文档
【发布时间】:2016-08-02 23:34:57
【问题描述】:

我目前正在尝试通过匹配数组上的文档来查询一个集合,让我们调用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 查询来解决这个问题有什么想法吗?

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

【问题讨论】:

    标签: mongodb meteor mongodb-query aggregation-framework


    【解决方案1】:

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

    此外,如果您想更多地过滤字段的投影,您可以应用聚合、展开并为您的文档进行投影。 看看我的示例 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
    

    【讨论】:

    • 将其标记为答案,因为这肯定回答了问题,但不幸的是,在 Meteor 框架中使用 mapReduce 的输出返回了一些意想不到的结果。如有必要,将解决更多问题并发布另一个问题。感谢您的宝贵时间!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-02-19
    • 1970-01-01
    • 1970-01-01
    • 2019-06-22
    • 1970-01-01
    • 1970-01-01
    • 2016-08-10
    相关资源
    最近更新 更多