2017-04-03 85 views
1

我想將mapReduce轉換爲聚合。MongoDB將mapReduce轉換爲聚合

我被卡住了,因爲我有多個調用在map()函數中發射()。我不明白我可以用$ group來做到這一點。

這裏的MapReduce的:

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

輸出:

{ 
    "_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 。一種方法是使用$facet階段,該階段允許您將管道拆分爲多個並行階段,另一種方法是創建一個數組字段,然後展開它,以便可以按類型和值的各種組合進行分組。

使用$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

隨着$方面:如果companyId /僱員沒有設置,我不想推在陣列公司/員工中的價值。可能嗎? – mathieug

+0

哦,我還可以在管道末端添加$匹配 – mathieug

+0

如何展開四個陣列? – mathieug