2016-05-05 5 views
1

私は以下のデータセットを持っています。アカウントでグループ化してElement_Fieldnameを列にする必要があります。Mongodbの集計行から列へ

var collection = [ 
    { 
     Account:12345, 
     Element_Fieldname:"cars", 
     Element_Value:true 
    }, 
    { 
     Account:12345, 
     Element_Fieldname:"boats", 
     Element_Value:false 
    } 
] 

これは行を列に変換しようとしましたが、機能しません。

db.getCollection('my_collection').aggregate([{ 
      $match : { 
       Element_Fieldname : { 
        $in : ["cars", "boats"] 
       } 
      } 
     }, { 
      $group : { 
       _id : "$Account", 
       values : { 
        $addToSet : { 
         field : "$Element_Fieldname", 
         value : "$Element_Value" 
        } 
       } 
      } 
     }, { 
      $project : { 
       Account : "$_id", 
       cars : { 
        "$cond" : [{ 
          $eq : ["$Element_Fieldname", "cars"] 
         }, "$Element_Value", null] 
       }, 
       boats : { 
        "$cond" : [{ 
          $eq : ["$Element_Fieldname", "day_before_water_bottles"] 
         }, "$Element_Value", null] 
       }, 
      } 
     } 
    ]) 

これはちょうど私に私carsboats分野でnullを与えます。どんな助けも素晴らしいだろう。

そして、これが私の望む結果である:

var desiredResult = [ 
    { 
     Account:12345, 
     cars:true, 
     boats:false 
    } 
] 

答えて

1

これは大きなトリッキーですが、あなたは

db.collection.aggregate([{ 
      $project : { 
       _id : 0, 
       "Account" : 1, 
       car : { 
        $cond : [{ 
          $eq : ["$Element_Fieldname", "cars"] 
         }, "$Element_Value", null] 
       }, 
       boats : { 
        $cond : [{ 
          $eq : ["$Element_Fieldname", "boats"] 
         }, "$Element_Value", null] 
       }, 
      } 
     }, 
     { 
      $group : { 
       _id : "$Account", 
       carData : { 
        $addToSet : "$car" 
       }, 
       boatsData : { 
        $addToSet : "$boats" 
       } 
      } 
     }, { 
      $unwind : "$carData" 
     }, { 
      $match : { 
       carData : { 
        $ne : null 
       } 
      } 
     }, { 
      $unwind : "$boatsData" 
     }, { 
      $match : { 
       boatsData : { 
        $ne : null 
       } 
      } 
     }, 
    ]) 

とはなり

が集約パイプラインの上に$の試合を追加してください:-)必要なものを取得します

{ 
    "_id" : 12345, 
    "carData" : true, 
    "boatsData" : false 
} 
+0

あなたはそれをすばらしく解決しました。あなたはこれがどのように大規模になると思いますか?私の作業データセットは何百万人にもなるでしょうか? – Rob

+0

まず、この場合はdisk:trueを使用する必要があります。プロセス自体は複雑ではないので、$ outを使用してこのレポートをすべてのユーザー要求で実行するのではなく、新しいコレクションに書き込もうとする可能性があります – profesor79

0

代わりにどのように配列に結果を置くことについての列に変換するの?この方法で、クエリを変更せずに、必要な数のフィールド名を設定できます。

db.collection.aggregate([ 
    {$group:{ 
     "_id": { 
      "account": "$Account", 
      "field": "$Element_Fieldname" 
     }, 
     count: {$sum: {$cond: ["$Element_Value", 1, 0]}} 
    }}, 
    {$group: { 
     "_id": "$_id.account", 
     "res": {$push: {"Element_Fieldname": "$_id.field", "Element_Value": {$gt: ["$count", 0]}}} 
    }} 
]) 
+0

ジョアン - 申し訳ありませんが、私はそれで両方の車やボートで一つのレコードを必要とするので、この文句を言わない仕事。これを実行すると、それぞれに1つずつ、2つの項目の配列が取得されます。 – Rob

+0

@Rob確かに、それが全体のポイントでした - あなたは各アカウントの結果と配列を取得します。だから私はそれがオプションかどうか分からなかったので、私は尋ねた。 – joao

0

集約フレームワークで記述している計算のタイプを行うことはできませんが、提案された$arrayToObjectという表現は、キー名を覗き込み、新しいキー/値を動的に作成する機能を提供します。

たとえば、あなたは、この機能を得るために、このJIRAチケットhttps://jira.mongodb.org/browse/SERVER-23310ため

db.collection.aggregate([ 
    { 
     "$match": { "Element_Fieldname":{ "$in": ["cars", "boats"] } } 
    },  
    { 
     "$group": { 
      "_id": "$Account", 
      "attrs": { 
       "$push": { 
        "key": "$Element_Fieldname", 
        "val": "$Element_Value" 
       } 
      }    
     } 
    }, 
    { 
     "$project": { 
      "Account": "$_id", 
      "_id": 0, 
      "newAttrs": { 
       "$arrayToObject": { 
        "$map": { 
         "input": "$attrs", 
         "as": "el", 
         in: ["$$el.key", "$$el.val"] 
        } 
       } 
      } 
     } 
    }, 
    { 
     "$project": { 
      "Account": 1, 
      "cars": "$newAttrs.cars", 
      "boats": "$newAttrs.boats" 
     } 
    } 
]) 

投票を行うことができます。


回避策として、mapreduceは利用可能なオプションのようです。次のマップ-減らす操作を実行している考えてみましょう:

db.collection.mapReduce(
    function() { 
     var obj = {}; 
     obj[this.Element_Fieldname] = this.Element_Value;   
     emit(this.Account, obj); 
    }, 
    function(key, values) { 
     var obj = {}; 
     values.forEach(function(value) { 
      Object.keys(value).forEach(function(key) {     
       obj[key] = value[key]; 
      }); 
     }); 
     return obj; 
    }, 
    { "out": { "inline": 1 } } 
) 

結果

{ 
    "_id" : 12345, 
    "value" : { 
     "cars" : true, 
     "boats" : false 
    } 
}