2017-07-27 38 views
0

我在使用MongoDb對數據進行分組時遇到問題。數組中的聚合總數

我有一些項目與一些進出運動,我想計算一個項目的總量與運動量,但運動不正確計算。

這裏是我的樣本數據,小的單子有兩股和一些運動....

/* 1 */ 
{ 
    "TemplateName" : "SAALottoStagionatura", 
    "idStock" : 31789, 
    "idWarehouse" : 191, 
    "StockCode" : "71529902", 
    "Marks" : [ 
     { 
      "idMark" : 20145, 
      "idWarehouse" : 191, 
      "idStock" : 31789, 
      "ProgressivoDocumento" : 486, 
      "Year" : 2016, 
      "RefDate" : ISODate("2016-03-28T22:00:00.000Z"), 
      "MarkedItems" : 72 
     }, 
     { 
      "idMark" : 20156, 
      "idWarehouse" : 191, 
      "idStock" : 31789, 
      "ProgressivoDocumento" : 497, 
      "Year" : 2016, 
      "RefDate" : ISODate("2016-03-30T22:00:00.000Z"), 
      "MarkedItems" : 144 
     }, 
     { 
      "idMark" : 23424, 
      "idWarehouse" : 191, 
      "idStock" : 31789, 
      "ProgressivoDocumento" : 840, 
      "Year" : 2016, 
      "RefDate" : ISODate("2016-06-12T22:00:00.000Z"), 
      "MarkedItems" : 3 
     } 
    ], 
    "Details" : [ 
     { 
      "idLSDetail" : 42781, 
      "idStock" : 31789, 
      "idStockOrig" : 54502, 
      "StockCode" : "71529902", 
      "Items" : 4532 
     } 
    ], 
    "MovementsOut" : [ 
     { 
      "idMovementDetail" : 633, 
      "idMovement" : 511, 
      "MovedItems" : 3528 , 
      "idStockOrig" : null, 
      "idStock" : 31789 
     } 
    ], 
    "MovementsIn" : [ 
     { 
      "idMovementDetail" : 715, 
      "idMovement" : 570, 
      "MovedItems" : 3528, 
      "idStockOrig" : null, 
      "idStock" : 33678 
     } 
    ] 
} 


/* 2 */ 
{ 
    "TemplateName" : "SAALottoStagionatura", 
    "idStock" : 33678, 
    "idWarehouse" : 190, 
    "StockCode" : "71529902", 
    "Marks" : [], 
    "Details" : [ 
     { 
      "idLSDetail" : 45206, 
      "idStock" : 33678, 
      "idStockOrig" : 56684, 
      "StockCode" : "71529902", 
      "Items" : 3528 

     } 
    ], 
    "MovementsOut" : [ 
     { 
      "idMovementDetail" : 715, 
      "idMovement" : 570, 
      "MovedItems" : 3528, 
      "idStockOrig" : null, 
      "idStock" : 33678 
     } 
    ], 
    "TrasferimentiInEntrata" : [] 
} 

,並在我的查詢我嘗試組運動

db.getCollection('Test') 
.aggregate(
[ 
     {$match: {"idWarehouse": 191, StockCode: "71529902" } }, 
     {$unwind: "$Details"}, 
     {$unwind: "$Marks"},  
     {$unwind: "$MovementsIn"},  
     {$unwind: "$MovementsOut"},  
     { 
     $group : { 
      _id : { 
       StockCode: "$idStock", 
       StockCode: "$StockCode" 
       }, 

      tot: { $sum: "$Details.Items" }, 
      cer: { $sum: "$Marks.MarkedItems" }, 
      in: { $sum: "$MovementsIn.MovedItems" }, 
      out: { $sum: "$MovementsOut.MovedItems" } 
     } 
     } 
    ] 
) 

我的期望應該是這樣的

{ 
    "_id" : { 
     "StockCode" : "71529902" 
    }, 
    "tot" : 13596, 
    "cer" : 219, 
    "in" : 3528, 
    "out" : 7056 
} 

但是我總是得到運動的全部總和(10584)in and out。我在哪裏錯了?

回答

1

其實在任何現代的MongoDB上映以來,3.2只需使用的$sum「雙barelled」調用,並沒有$unwind可言:

db.getCollection('Test').aggregate([ 
    { "$group": { 
    "_id": { 
     "StockCode": "$StockCode" 
    }, 
    "tot": { "$sum": { "$sum": "$Details.Items" } }, 
    "cer": { "$sum": { "$sum": "$Marks.MarkedItems" } }, 
    "in": { "$sum": { "$sum": "$MovementsIn.MovedItems" } }, 
    "out": { "$sum": { "$sum": "$MovementsOut.MovedItems" } } 
    }} 
]) 

這是因爲該版本,當你譜寫一個元素在諸如"$Details.Items"的數組中,投影結果是在指定路徑中找到的「值的數組」。第二個補充是$sum也是「總和數組」,所以它在組中被調用爲$sum數組內容,然後$sum作爲文件之間的「累加器」。

/* 1 */ 
{ 
    "_id" : { 
     "StockCode" : "71529902" 
    }, 
    "tot" : 8060.0, 
    "cer" : 219.0, 
    "in" : 3528.0, 
    "out" : 7056.0 
} 

在早期版本如MongoDB的2.6你可以避開「笛卡爾積」,這是$unwind多個結果:

時,針對你的問題的兩個文件運行返回結果由陣列組合成一個,可能使用$setUnion陣列如果標識符和值實際上唯一的:

db.getCollection('Test').aggregate([ 
    { "$project": { 
    "StockCode": 1, 
    "combined": { 
     "$setUnion": [ 
     { "$map": { 
      "input": { "$ifNull": [ "$Details", [] ] }, 
      "as": "el", 
      "in": { "id": "$idLSDetail", "k": "Details", "v": "$$el.Items" } 
     }}, 
     { "$map": { 
      "input": { "$ifNull": [ "$Marks", [] ] }, 
      "as": "el", 
      "in": { "id": "$idMark", "k": "Marks", "v": "$$el.MarkedItems" } 
     }}, 
     { "$map": { 
      "input": { "$ifNull": [ "$MovementsIn", [] ] }, 
      "as": "el", 
      "in": { "id": "$idMovementDetail", "k": "MoveIn", "v": "$$el.MovedItems" } 
     }}, 
     { "$map": { 
      "input": { "$ifNull": [ "$MovementsOut", [] ] }, 
      "as": "el", 
      "in": { "id": "$idMovementDetail", "k": "MoveOut", "v": "$$el.MovedItems" } 
     }} 
     ] 
    } 
    }}, 
    { "$unwind": "$combined" }, 
    { "$group": { 
    "_id": { 
     "StockCode": "$StockCode" 
    }, 
    "tot": { 
     "$sum": { 
     "$cond": { 
      "if": { "$eq": [ "$combined.k", "Details" ] }, 
      "then": "$combined.v", 
      "else": 0 
     } 
     } 
    }, 
    "cer": { 
     "$sum": { 
     "$cond": { 
      "if": { "$eq": [ "$combined.k", "Marks" ] }, 
      "then": "$combined.v", 
      "else": 0 
     } 
     } 
    }, 
    "in": { 
     "$sum": { 
     "$cond": { 
      "if": { "$eq": [ "$combined.k", "MoveIn" ] }, 
      "then": "$combined.v", 
      "else": 0 
     } 
     } 
    }, 
    "out": { 
     "$sum": { 
     "$cond": { 
      "if": { "$eq": [ "$combined.k", "MoveOut" ] }, 
      "then": "$combined.v", 
      "else": 0 
     } 
     } 
    } 
    }} 
]) 

而我n舊版本或確實無法實現「唯一性」的情況下,您分別替換每個陣列,然後重複該過程,直到陣列「減少」爲止。然後你可以將$group作爲最終的文件。

但是和上面一樣,你需要注意,因爲並不是所有的文件都有所有的數組,所以需要處理。在上面的例子中,我們可以提供一個「空」數組而不是null(在最初的$sum並不在意)。但是,一旦你在每次使用$unwind單獨你進入的問題,如果沒有什麼存在或爲空:

db.getCollection('Test').aggregate([ 
    { "$project": { 
    "StockCode": 1, 
    "Details": { 
     "$cond": [ 
      { "$eq": [{ "$size": { "$ifNull": [ "$Details", [] ] } }, 0] }, 
      [null], 
      "$Details" 
     ] 
    }, 
    "Marks": { 
     "$cond": [ 
      { "$eq": [{ "$size": { "$ifNull": [ "$Marks", [] ] } }, 0] }, 
      [null], 
      "$Marks" 
     ] 
    }, 
    "MovementsIn": { 
     "$cond": [ 
      { "$eq": [{ "$size": { "$ifNull": [ "$MovementsIn", [] ] } }, 0] }, 
      [null], 
      "$MovementsIn" 
     ] 
    }, 
    "MovementsOut": { 
     "$cond": [ 
      { "$eq": [{ "$size": { "$ifNull": [ "$MovementsOut", [] ] } }, 0] }, 
      [null], 
      "$MovementsOut" 
     ] 
    } 
    }}, 
    { "$unwind": "$Details" }, 
    { "$group": { 
    "_id": "$_id", 
    "StockCode": { "$first": "$StockCode" }, 
    "tot": { "$sum": "$Details.Items" }, 
    "Marks": { "$first": "$Marks" }, 
    "MovementsIn": { "$first": "$MovementsIn" }, 
    "MovementsOut": { "$first": "$MovementsOut" }  
    }}, 
    { "$unwind": "$Marks" }, 
    { "$group": { 
    "_id": "$_id", 
    "StockCode": { "$first": "$StockCode" }, 
    "tot": { "$first": "$tot" }, 
    "cer": { "$sum": "$Marks.MarkedItems" }, 
    "MovementsIn": { "$first": "$MovementsIn" }, 
    "MovementsOut": { "$first": "$MovementsOut" }  
    }}, 
    { "$unwind": "$MovementsIn" }, 
    { "$group": { 
    "_id": "$_id", 
    "StockCode": { "$first": "$StockCode" }, 
    "tot": { "$first": "$tot" }, 
    "cer": { "$first": "$cer" }, 
    "in": { "$sum": "$MovementsIn.MovedItems" }, 
    "MovementsOut": { "$first": "$MovementsOut" }  
    }}, 
    { "$unwind": "$MovementsOut" }, 
    { "$group": { 
    "_id": "$_id", 
    "StockCode": { "$first": "$StockCode" }, 
    "tot": { "$first": "$tot" }, 
    "cer": { "$first": "$cer" }, 
    "in": { "$first": "$in" }, 
    "out": { "$sum": "$MovementsOut.MovedItems" }  
    }}, 
    { "$group": { 
    "_id": { 
     "StockCode": "$StockCode", 
    }, 
    "tot": { "$sum": "$tot" }, 
    "cer": { "$sum": "$cer" }, 
    "in": { "$sum": "$in" }, 
    "out": { "$sum": "$out" } 
    }} 
]) 

所以有該項測試需要$ifNull$size摸出如果陣列需要更換與否。

+0

非常清楚和完整的答案。非常感謝! – Grappachu