2013-10-09 10 views
11

MongoDB集約フレームワークを使用しているときに配列フィールドをマージすることは可能ですか?集約のためのMongoDB集約で配列フィールドをマージする

サンプル入力文書:

{ 
    "Category" : 1, 
    "Messages" : ["Msg1", "Msg2"], 
    "Value" : 1 
}, 
{ 
    "Category" : 1, 
    "Messages" : [], 
    "Value" : 10 
}, 
{ 
    "Category" : 1, 
    "Messages" : ["Msg1", "Msg3"], 
    "Value" : 100 
}, 
{ 
    "Category" : 2, 
    "Messages" : ["Msg4"], 
    "Value" : 1000 
}, 
{ 
    "Category" : 2, 
    "Messages" : ["Msg5"], 
    "Value" : 10000 
}, 
{ 
    "Category" : 3, 
    "Messages" : [], 
    "Value" : 100000 
} 

「価値」を合計し、「メッセージ」をマージしながら、私たちは「カテゴリー」でグループ化したいここで私が解決しようとしています要約問題があります。私は、この集約パイプラインを試してみました:

{group : { 
     _id : "$Category", 
     Value : { $sum : "$Value"}, 
     Messages : {$push : "$Messages"} 
    } 
}, 
{$unwind : "$Messages"}, 
{$unwind : "$Messages"}, 
{$group : { 
     _id : "$_id", 
     Value : {$first : "$Value"}, 
     Messages : {$addToSet : "$Messages"} 
    } 
} 

結果は次のとおりです。「カテゴリーが3」である文書は、任意の「メッセージ」と彼らを持っていないので、

"result" : [{ 
     "_id" : 1, 
     "Value" : 111, 
     "Messages" : ["Msg3", "Msg2", "Msg1"] 
    }, 
    { 
     "_id" : 2, 
     "Value" : 11000, 
     "Messages" : ["Msg5", "Msg4"] 
    } 
] 

しかし、これは完全にカテゴリ3をミス第2巻き戻しによって落とされる。我々としても、以下が含まれるように結果を希望:

{ 
    "_id" : 3, 
    "Value" : 100000, 
    "Messages" : [] 
} 

は、集約フレームワークによって、これを達成するためのきちんとした方法はありますか?ここで

+0

を超え

db.messages.aggregate([ {"$group":{"_id":"$Category","Value":{"$sum":"$Value"},"Messages":{"$push":"$Messages"}}}, {"$unwind":{"path":"$Messages","preserveNullAndEmptyArrays":true}}, {"$unwind":{"path":"$Messages","preserveNullAndEmptyArrays":true}}, {"$group":{"_id":"$_id","Value":{"$first":"$Value"},"Messages":{"$addToSet":"$Messages"}}} ]) 

は、メッセージは配列としてそこにあることが保証されていますか?あるいは存在しないか、そこに存在する可能性はありますか? –

+0

yesメッセージは配列として存在することが保証されています(一部のレコードでは空の場合があります)。 – etkarayel

+0

あなたは 'preserveNullAndEmptyArrays'オプションを' $ unwind'にしようとしましたか? –

答えて

12

は、メッセージは配列であることが保証された場合に使用できるトリックです:

> db.messages.find() 
    { "Category" : 1, "Messages" : [ "Msg1", "Msg2" ], "Value" : 1 } 
    { "Category" : 1, "Messages" : [ ], "Value" : 10 } 
    { "Category" : 1, "Messages" : [ "Msg1", "Msg3" ], "Value" : 100 } 
    { "Category" : 2, "Messages" : [ "Msg4" ], "Value" : 1000 } 
    { "Category" : 2, "Messages" : [ "Msg5" ], "Value" : 10000 } 
    { "Category" : 3, "Messages" : [ ], "Value" : 100000 } 

> var group1 = { 
    "$group": { 
     "_id":  "$Category", 
     "Value": { 
      "$sum":  "$Value" 
     }, 
     "Messages": { 
      "$push": "$Messages" 
     } 
    } 
}; 

> var project1 = { 
    "$project": { 
     "Value": 1, 
     "Messages": { 
      "$cond": [ 
       { 
        "$eq": [ 
         "$Messages", 
         [ [ ] ] 
        ] 
       }, 
       [ [ null ] ], 
       "$Messages" 
      ] 
     } 
    } 
}; 

> db.messages.aggregate(group1, project1) 
    { "_id" : 3, "Value" : 100000, "Messages" : [ [ null ] ] } 
    { "_id" : 2, "Value" : 11000, "Messages" : [ [ "Msg4" ], [ "Msg5" ] ] } 
    { "_id" : 1, "Value" : 111, "Messages" : [ [ "Msg1", "Msg2" ], [ ], [ "Msg1", "Msg3" ] ] } 

今、単一のメッセージの配列を取得するために二回、再グループおくつろぎください。

> var unwind = {"$unwind":"$Messages"}; 

> var group2 = { 
    $group: { 
     "_id":  "$_id", 
     "Value": { 
      "$first":  "$Value" 
     }, 
     "Messages": { 
      "$addToSet": "$Messages" 
     } 
    } 
}; 

> var project2 = { 
    "$project": { 
     "Category": "$_id", 
     "_id":  0, 
     "Value": 1, 
     "Messages": { 
      "$cond": [ 
       { 
        "$eq": [ 
         "$Messages", 
         [ null ] 
        ] 
       }, 
       [ ], 
       "$Messages" 
      ] 
     } 
    } 
}; 

> db.messages.aggregate(group1, project1, unwind, unwind, group2 ,project2) 
    { "Value" : 111, "Messages" : [ "Msg3", "Msg2", "Msg1" ], "Category" : 1 } 
    { "Value" : 11000, "Messages" : [ "Msg5", "Msg4" ], "Category" : 2 } 
    { "Value" : 100000, "Messages" : [ ], "Category" : 3 } 
+0

ヒントをありがとう。それは私が必要とするものをほとんど実行します。しかし、所望の結果が得られない場合があります。カテゴリ1の集計結果(元の投稿の文書に基づく)は、[Msg1]、[Msg2]、[Msg3]、[dummy]の4つのメッセージで終了します。私はこのケースで「ダミー」を簡単に取り除く方法についてはわかりません。 – etkarayel

+0

右 - それを取り除く方法があります - 私は答えを更新します –

+0

今、すべてのステップで完全な答えが - 正確にあなたが望むものでなければなりません:) –

0

3.2バージョンで以下の集計クエリを試すことができます。 3.4バージョンの場合と

db.messages.aggregate([ 
    {"$group":{"_id":"$Category","Value":{"$sum":"$Value"},"Messages":{"$push":"$Messages"}}}, 
    {"$addFields":{ 
    "Messages":{ 
     "$reduce":{ 
     "input":"$Messages", 
     "initialValue":[], 
     "in":{"$setUnion":["$$value","$$this"]} 
     } 
    } 
    } 
    } 
]) 
関連する問題