Mongodb 从数组中聚合总计
我在使用MongoDb分组数据时遇到问题 我有一堆有一些进出运动的项目,我想计算一个有运动量的项目摘要,但运动计算不正确 这是我的样本数据,一个包含两支股票和一些走势的小列表Mongodb 从数组中聚合总计,mongodb,aggregation-framework,Mongodb,Aggregation Framework,我在使用MongoDb分组数据时遇到问题 我有一堆有一些进出运动的项目,我想计算一个有运动量的项目摘要,但运动计算不正确 这是我的样本数据,一个包含两支股票和一些走势的小列表 /* 1 */ { "TemplateName" : "SAALottoStagionatura", "idStock" : 31789, "idWarehouse" : 191, "StockCode" : "71529902", "Marks" : [ {
/* 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的全部总和。我错在哪里?事实上,在3.2版之后的任何现代MongoDB版本中,您只需使用的是双裸调用,而不是: 这是因为从该版本开始,当您对数组(如$Details.Items)中的元素进行注释时,投影结果是在指定路径上找到的一个值数组。第二个附加功能是对数组求和,因此它在组中被调用到数组内容,然后作为文档之间的累加器 针对问题中的两个文档运行时返回结果:
/* 1 */
{
"_id" : {
"StockCode" : "71529902"
},
"tot" : 8060.0,
"cer" : 219.0,
"in" : 3528.0,
"out" : 7056.0
}
在早期版本(如MongoDB 2.6)中,您可以通过将多个数组组合成一个数组来避免笛卡尔积,如果标识符和值实际上是唯一的,则可能使用:
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
}
}
}
}}
])
在较旧的版本中,或者在不可能唯一性的情况下,可以分别替换每个数组,然后重复此过程,直到减少数组。然后,您可以将$group作为跨文档的最终值
但与上面一样,您需要小心,因为并非所有文档都有所有数组,这需要处理。在上面的示例中,我们可以只提供一个空数组,而不是初始$sum中的null。但是,一旦您单独使用,如果没有任何内容或内容为空,则会出现问题:
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" }
}}
])
因此,那里的测试需要确定阵列是否需要更换 非常清楚和完整的答案。非常感谢你!
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" }
}}
])