2017-04-03 21 views
1

mapReduceを集約に変換しようとしています。MongoDBからmapReduceを集約に変換する

私はmap()関数でemit()を複数回呼び出すために立ち往生していません。私は$ groupでそれをどうやってやることができないのか分かりません。

function map() { 
    const dateHour = this.createdAt.toISOString().substr(0, 13); 
    const value = { 
    orders: 1, 
    amount: this.amount 
    }; 

    emit({ 
    date: dateHour, 
    type: 'global', 
    granularity: 'hour' 
    }, value); 

    if (this.companyId) { 
    emit({ 
     date: dateHour, 
     type: 'company', 
     companyId: this.companyId, 
     granularity: 'hour' 
    }, value); 
    } 

    if (this.employeeId) { 
    emit({ 
     date: dateHour, 
     type: 'employee', 
     employeeId: this.employeeId, 
     granularity: 'hour' 
    }, value); 
    } 

    emit({ 
    date: dateHour, 
    type: 'kitchen', 
    kitchenId: this.kitchenId, 
    granularity: 'hour' 
    }, value); 
} 

function reduce(key, values) { 
    return values.reduce((accumulator, value) => ({ 
    orders: accumulator.orders + value.orders, 
    amount: accumulator.amount + value.amount, 
    }), { 
    orders: 0, 
    amount: 0 
    }); 
} 

サンプル入力:

{ 
    "_id" : ObjectId("586f5fc7f3f3bf001178e2bf"), 
    "deliverySlotStart" : ISODate("2017-01-06T11:00:00.000+0000"), 
    "amount" : 11.0 
    "kitchenId" : ObjectId("5858154c3aa80f1120c78c08"), 
    "createdAt" : ISODate("2017-01-06T09:13:43.354+0000"), 
} 
{ 
    "_id" : ObjectId("586f657ef3f3bf001178e2c0"), 
    "deliverySlotStart" : ISODate("2017-01-06T11:00:00.000+0000"), 
    "amount" : 11.0 
    "kitchenId" : ObjectId("5858154c3aa80f1120c78c08"), 
    "createdAt" : ISODate("2017-01-06T09:38:06.174+0000"), 
    "employeeId" : ObjectId("58948c82f1efa800115a484e"), 
    "companyId" : ObjectId("5891d7dd50b5e76b7733f27b") 
} 

出力:ここ

は、MapReduceのだ

{ 
    "_id" : { 
     "date" : "2017-01-06T09", 
     "type" : "company", 
     "companyId" : ObjectId("5891d7dd50b5e76b7733f27b"), 
     "granularity" : "hour" 
    }, 
    "value" : { 
     "orders" : 1.0, 
     "amount" : 11.0 
    } 
} 
{ 
    "_id" : { 
     "date" : "2017-01-06T09", 
     "type" : "employee", 
     "employeeId" : ObjectId("58948c82f1efa800115a484e"), 
     "granularity" : "hour" 
    }, 
    "value" : { 
     "orders" : 1.0, 
     "amount" : 11.0 
    } 
} 
{ 
    "_id" : { 
     "date" : "2017-01-06T09", 
     "type" : "global", 
     "granularity" : "hour" 
    }, 
    "value" : { 
     "orders" : 2.0, 
     "amount" : 22.0 
    } 
} 
{ 
    "_id" : { 
     "date" : "2017-01-06T09", 
     "type" : "kitchen", 
     "kitchenId" : ObjectId("5858154c3aa80f1120c78c08"), 
     "granularity" : "hour" 
    }, 
    "value" : { 
     "orders" : 2.0, 
     "amount" : 22.0 
    } 
} 
+0

私のMongoDBサーバのバージョンが$ファセットで3.4 – mathieug

答えて

2

あなたが3.4に集約してやろうとしているものには2つの方法があります。 。 1つの方法は、パイプラインを複数の並列ステージに分割することができる$facetステージを使用することです。もう1つは、配列フィールドを作成してから巻き戻し、タイプと値のさまざまな組み合わせでグループ化できます。

$facetを使用する:

db.coll.aggregate([ 
    {$addFields:{dh:{$dateToString:{format:"%Y-%m-%dT%H",date:"$createdAt"}}}}, 
    {$facet:{ 
     global:[ 
      {$group:{_id:{dateHour:"$dh", type: "global"}, 
        orders:{$sum:1}, 
        amount:{$sum:"$amount"}}} ], 
     company:[ 
      {$group:{_id:{dateHour:"$dh", type: "company"}, 
        orders:{$sum:{$cond:[{$eq:[{$ifNull:["$companyId",null]},null]},0,1]}}, 
        amount:{$sum:{$cond:[{$eq:[{$ifNull:["$companyId",null]},null]},0,"$amount"]}} }} ], 
     employee:[ 
      {$group:{_id:{dateHour:"$dh", type: "employee"}, 
        orders:{$sum:{$cond:[{$eq:[{$ifNull:["$employeeId",null]},null]},0,1]}}, 
        amount:{$sum:{$cond:[{$eq:[{$ifNull:["$employeeId",null]},null]},0,"$amount"]}} }} ], 
     kitchen:[ 
      {$group:{_id:{dateHour:"$dh", type: "kitchen"}, 
        orders:{$sum:{$cond:[{$eq:[{$ifNull:["$kitchenId",null]},null]},0,1]}}, 
        amount:{$sum:{$cond:[{$eq:[{$ifNull:["$kitchenId",null]},null]},0,"$amount"]}} }} ] 
    }} 
]) 

生成列:

db.coll.aggregate([ 
    {$addFields:{ 
    a:{$let:{ 
     vars: {dh:{$dateToString:{format:"%Y-%m-%dT%H",date:"$createdAt"}}}, 
     in: { 
      dateHour:"$$dh", 
      t:[ 
       {type:"global"}, 
       {$cond:[{$eq:[{$ifNull:["$companyId",null]},null]}, "", {type:"company", companyId:"$companyId"}]}, 
       {$cond:[{$eq:[{$ifNull:["$employeeId",null]},null]}, "", {type:"employee", employeeId:"$employeeId"}]}, 
       {$cond:[{$eq:[{$ifNull:["$kitchenId",null]},null]}, "", {type:"kitchen", kitchenId:"$kitchenId"}]} 
      ] 
    }}}}}, 
    {$unwind:"$a.t"}, 
    {$match:{"a.t":{$ne:""}}}, 
    {$group:{ 
     _id:{date:"$a.dateHour", type:"$a.t.type", companyId:"$a.t.companyId", kitchenId:"$a.t.kitchenId", employeeId:"$a.t.employeeId", granularity:"hour"}, 
     orders:{$sum:1}, 
     amount:{$sum:"$amount"}}}, 
    {$sort:{"_id.type":1}} 
]) 
+0

です:企業ID /社員が設定されていない場合は、私がプッシュする必要はありません配列company/employeeの値。出来ますか? – mathieug

+0

ああ、パイプラインの最後に$一致を追加することもできます – mathieug

+0

4つの配列をどのように巻き戻すことができますか? – mathieug

関連する問題