【问题标题】:Mongo DB - usage of map reduce or aggregationMongodb - map reduce或aggregation的使用
【发布时间】:2016-03-26 03:18:42
【问题描述】:

我在 MongoDB 集合中有一系列文档,如下所示:

{ 'time' : '2016-03-28 12:12:00', 'value' : 90 },
{ 'time' : '2016-03-28 12:13:00', 'value' : 82 },
{ 'time' : '2016-03-28 12:14:00', 'value' : 75 },
{ 'time' : '2016-03-28 12:15:00', 'value' : 72 },
{ 'time' : '2016-03-28 12:16:00', 'value' : 81 },
{ 'time' : '2016-03-28 12:17:00', 'value' : 90 },
etc....

任务是 - 垃圾保留值为 80 的所有时间,查找值低于 80 的 entering 和高于 80 的 exiting

{ 'time' : '2016-03-28 12:14:00', 'result' : 'enter' },
{ 'time' : '2016-03-28 12:16:00', 'result' : 'exit' },

有没有办法让 map reduce 或聚合查询产生这样的结果? 我试图循环遍历排序的结果,但它的处理和内存非常昂贵 - 我需要进行一系列此类检查。

PS。我正在使用 Django 和 mongoengine 来执行调用。

【问题讨论】:

  • 不投票作为“重复”(尚未),因为您的情况有点不清楚。看起来顺序迭代就是你真正想要的。您可以像这里的示例那样“强制”mapReduce 吐出结果,但除非您真的获得了一些东西,否则您可能不应该这样做。请注意,聚合框架根本无法像您在此处需要的那样在文档之间“跟踪”。
  • time 字段是否有重复项?如果value 是80,result 是什么?
  • 好吧,如果value 是 80,我根据 OP 描述将其读作“排除”。

标签: django mongodb mongoengine


【解决方案1】:

我不确定单独使用 MongoDB 聚合框架是否可行,因为正如@BlakesSeven 所提到的,后续文档之间没有链接/连接。您需要此连接来检查新值是否低于或高于所需阈值,与之前文档中的值相比。

这是一个天真的 pure-python(因为它被 Django 和 MongoEngine 标记)解决方案循环遍历排序结果,维护阈值跟踪变量并在它变低或变高时捕获 80 ( col 是您的收藏参考):

THRESHOLD = 80
cursor = col.find().sort("time")

first_value = next(cursor)
more_than = first_value["value"] >= THRESHOLD

for document in cursor:
    if document["value"] < THRESHOLD:
        if more_than:
            print({"time": document["time"], "result": "enter"})
        more_than = False
    else:
        if not more_than:
            print({"time": document["time"], "result": "exit"})
        more_than = True

对于提供的示例数据,它会打印:

{'time': '2016-03-28 12:14:00', 'result': 'enter'}
{'time': '2016-03-28 12:16:00', 'result': 'exit'}

作为旁注和替代解决方案..如果您可以控制这些记录的插入方式,当您将文档插入此集合时,您可以检查最新的 value 是什么,并将其与阈值进行比较并将result 设置为单独的字段。然后,查询进入和退出阈值点将变得如此简单:

col.find({"result" : {$exists : true}})

您可以将此方法命名为“预先标记阈值”。这可能仅从查询/搜索性能的角度来看才有意义,并且如果您要经常这样做。

【讨论】:

    【解决方案2】:

    借助聚合框架和游标迭代,您可以轻松实现文档的转换。

    例子:

    db.collection.aggregate([
      {$project:
        {
          value:1,
          "threshold":{$let:
            {
              vars: {threshold: 80 }, 
              in:   "$$threshold"
            }}
         }
      },
      {$match:{value:{$ne: "$threshold"}}},
      {$group:
         {
           _id:"$null", 
           low:{
             $max:{
                 $cond:[{$lt:["$value","$threshold"]},"$value",-1]
              }
           },
    
           high:{
             $min:{
                 // 10000000000 is a superficial value. 
                 // need something greater than values in documents
                 $cond:[{$gt:["$value","$threshold"]},"$value",10000000000] 
              }
           },
    
           threshold:{$first:"$threshold"}
         }
       }  
    ])
    

    聚合框架将返回一个包含两个值的文档。

    { 
        "_id" : null, 
        "low" : NumberInt(75), 
        "high" : NumberInt(81), 
        "threshold" : NumberInt(80)
    }
    

    我们可以轻松找到符合退货条件的文件。例如在 NodeJS 中,我们可以轻松做到这一点。假设变量 result 保存聚合查询的结果。

    result.forEach(function(r){
    
       var documents = [];
    
       db.collection.find({$or:[{"value": r.low},{"value": r.high}]}).forEach(function(doc){
    
            var _doc = {};
            _doc.time = doc.time;
            _doc.result = doc.value < r.threshold ? "enter" : "exit";
            documents.push(_doc);
       });
       printjson(documents);
    });
    

    正如您提到的,如果您的输入文档是(示例)

    { 'time' : '2016-03-28 12:12:00', 'value' : 90 },
    { 'time' : '2016-03-28 12:13:00', 'value' : 82 },
    { 'time' : '2016-03-28 12:14:00', 'value' : 75 },
    { 'time' : '2016-03-28 12:15:00', 'value' : 72 },
    { 'time' : '2016-03-28 12:16:00', 'value' : 81 },
    { 'time' : '2016-03-28 12:17:00', 'value' : 90 },
    etc....
    

    解决方案中的上述查询将发出:

    {
        "time" : "2016-03-28 12:14:00", 
        "result" : "enter"
    }, 
    {
        "time" : "2016-03-28 12:16:00", 
        "result" : "exit"
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-05-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多