2016-03-26 3 views
6

私はこのようになりますMongoDBのコレクション内の一連の文書があります:タスクモンゴDB - マップの使用削減や凝集

{ '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のゴミホールド値と値は以下のenteringあるすべての時間を見つけます80

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

上記80とexitingは、このような結果を生み出すことのマップが軽減持つ方法や集計クエリのですか? ソートされた結果をループさせようとしていましたが、非常に処理されてメモリが高価です - 私はそのような一連のチェックを行う必要があります。

PS。私はDjangoとmongoengineを使って呼び出しを実行しています。

+0

可能性のある重複した[ベースの最大連続レコードの数を探しますMongodbクエリの1つのフィールド](http://stackoverflow.com/questions/21621754/find-count-of-maximum-consecutive-records-based-on-one-field-in-mongodb-query)? –

+1

"dup"(まだ)として投票していません。あなたのケースが少し不明であるからです。逐次反復はあなたが本当に欲しいものです。ここで示したように結果を吐き出すためにmapReduceを「強制」することができますが、実際に何かを得ていない限り、そうしないでください。アグリゲーションフレームワークは、ここで必要なようにドキュメント間を単に追跡することはできません。 –

+0

'time'フィールドに重複がありますか? 'value'が80の場合、' result'は何になりますか? –

答えて

2

@BlakesSevenで述べたように、MongoDB集約フレームワークだけではこれが可能であるかどうかはわかりませんが、後続のドキュメント間にリンク/接続はありません。また、新しい値が希望のしきい値を下回ったかどうかを確認するには、前のドキュメントの値の直前の値と比較する必要があります。ソートされた結果、閾値トラック変数を維持し、それが低いか高くなるときキャッチをループ溶液(それはジャンゴとMongoEngineでタグ付けされているため)ここで

は80( colがあなたのコレクションであるナイーブ 純粋-pythonのです参照):提供されたサンプルデータについて

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}}) 

あなたは「事前にしきい値をマーキング」として、このアプローチに名前を付けることができます。これはおそらく、パフォーマンスの観点からのクエリ/検索と、これを頻繁に行うつもりである場合にのみ意味があります。

1

アグリゲーションフレームワークとカーソル反復の助けを借りて、簡単にドキュメントを変換することができます。

例:

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"} 
    } 
    } 
]) 

集約フレームワークは、2つの値を使用して文書を返します。

{ 
    "_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" 
} 
関連する問題