aggregate()
!を使用して作業を行う方が簡単で、はるかに高速です。
を使用し$project
て各イベントのカウンター フィールドを作成し、イベントが一致する場合はドキュメントからカウントを入力し、そうでない場合はゼロにします。次に$group
、ユーザー ID ごとに、すべてのイベント カウンターを合計します。
説明のために、最初に、例の 2 つの異なるイベント (1 と 2) に対してこれがどのようにハードコーディングされているかを示しましょう。
db.xx.aggregate([
{ $project: { userid:1,
cnt_e1: { $cond: [ { $eq: [ "$event", 1 ] }, "$count", 0 ] },
cnt_e2: { $cond: [ { $eq: [ "$event", 2 ] }, "$count", 0 ] },
} },
{ $group: { _id: "$userid", cnt_e1: { $sum: "$cnt_e1" }, cnt_e2: { $sum: "$cnt_e2" } } },
{ $sort: { _id: 1 } },
])
指定されたコレクションの場合:
> db.xx.find({},{_id:0})
{ "userid" : 1, "event" : 1, "count" : 10 }
{ "userid" : 1, "event" : 1, "count" : 15 }
{ "userid" : 1, "event" : 2, "count" : 12 }
{ "userid" : 2, "event" : 1, "count" : 5 }
{ "userid" : 3, "event" : 2, "count" : 10 }
結果は次のとおりです。
{
"result" : [
{
"_id" : 1,
"cnt_e1" : 25,
"cnt_e2" : 12
},
{
"_id" : 2,
"cnt_e1" : 5,
"cnt_e2" : 0
},
{
"_id" : 3,
"cnt_e1" : 0,
"cnt_e2" : 10
}
],
"ok" : 1
}
可変イベントに対してこれを行うには、プロジェクションとグループ化を生成する必要があります。コマンドを使用して、考えられるすべてのイベントの配列を取得しますdistinct()
(「イベント」にインデックスを定義したい場合があります)。次に、配列をループして、2 つのステートメントを JSON オブジェクトとして作成します。
project = {};
project.$project = {};
project.$project.userid = 1;
group = {};
group.$group = {};
group.$group._id = '$userid'
events = db.xx.distinct( "event" );
events.forEach( function( e ) {
field = "cnt_e" + e;
eval("project.$project." + field + " = {}");
eval("project.$project." + field + ".$cond = []");
eval("project.$project." + field + ".$cond[0] = {}");
eval("project.$project." + field + ".$cond[0].$eq = []");
eval("project.$project." + field + ".$cond[0].$eq[0] = '$event'");
eval("project.$project." + field + ".$cond[0].$eq[1] = " + e );
eval("project.$project." + field + ".$cond[1] = '$count'");
eval("project.$project." + field + ".$cond[2] = 0");
eval("group.$group." + field + " = {}");
eval("group.$group." + field + ".$sum = '$" + field + "'");
});
//printjson(project);
//printjson(group);
db.xx.aggregate([
project,
group,
{ $sort: { _id: 1 } },
])
そして、結果は上記と同じです。
注:上記は数値イベントで機能します。それらが文字列の場合、ジェネレーターを適応させる必要があります。
一見すると、これは @Philipp の mapReduce よりも複雑に見えるかもしれません。ただし、それは各ユーザーのすべてのイベントを返すわけではなく、カウントがあるイベントのみを返します。垂直方向から水平方向への完全なマッピングを行うには、map と reduce 関数も生成する必要があります。
aggregate() の詳細については、http://docs.mongodb.org/manual/aggregation/を参照してください。