我收到了预订,其中有几张发票,每张发票都有几张发票线。
我希望我的汇总选择加入发票的预订,然后只给我所有invoiceLines.amountTotal的总额。
示例预订表:
{
"_id" : "0PDLR",
"checkin" : 1488326400,
"checkout" : 1498780800,
}
示例发票表:
{
"_id" : 1,
"bookingId" : "0PDLR",
"invoiceLines" : [
{
"lineText" : "Rent Price",
"amountTotal" : 3000
},
{
"lineText" : "Discount",
"amountTotal" : -500
},
]
}
{
"_id" : 2,
"bookingId" : "0PDLR",
"invoiceLines" : [
{
"lineText" : "Final cleaning",
"amountTotal" : 200
},
]
}
{
"_id" : 3,
"bookingId" : "0PDLR",
"invoiceLines" : [
{
"lineText" : "Taxi to Airport",
"amountTotal" : 300
},
{
"lineText" : "Reservation fee paid already",
"amountTotal" : -500
}
]
}
这是我想得到的结果:
booking Result: [
{
"_id": "0PDLR",
"checkin": 1488326400,
"checkout": 1498780800,
"sum": 2500
}
]
这是我目前的汇总管道:
bookingTable.aggregate([
{ "$match": myMatch },
{
$lookup: {
from: "invoice",
localField: "_id",
foreignField: "bookingId",
as: "invoice"
}
},
{
$project:{
"_id" : 1,
"checkin" : 1,
"checkout" : 1,
"invoiceLines" : "$invoice.invoiceLines"
}
}
])
其中一个原因只是一个接一个地返回所有发票行的预订,
所以我将不得不遵循惯例:
var invoiceTotal = 0;
for (var i=0; i<selectBooking[b].invoiceLines.length; i++) {
for (var x=0; x<selectBooking[b].invoiceLines.length; x++) {
for (var y=0; y<selectBooking[b].invoiceLines[x].length; y++) {
invoiceTotal += selectBooking[b].invoiceLines[x][y].amountTotal
}
}
}
所以我的问题是,我可以在MongoDB中这样做吗?
有没有办法让它计算所有invoiceLines.amountTotal然后只返回$ project中的总和?
答案 0 :(得分:1)
这至少需要MongoDB 3.2,但您可以使用$map
和$sum
bookingTable.aggregate([
{ "$match": myMatch },
{ "$lookup": {
"from": "invoice",
"localField": "_id",
"foreignField": "bookingId",
"as": "invoice"
}},
{ "$project": {
"checkin" : 1,
"checkout" : 1,
"bookingTotal": {
"$sum": {
"$map": {
"input": "$invoice",
"as": "iv",
"in": {
"$sum": {
"$map": {
"input": "$$iv.invoiceLines",
"as": "il",
"in": "$$il.amountTotal"
}
}
}
}
}
}
}}
])
这实际上只是迭代每个数组,并将结果从"amountTotal"
减少到每一行的单个值。
使用3.4,您可以使用$reduce
:
bookingTable.aggregate([
{ "$match": myMatch },
{ "$lookup": {
"from": "invoice",
"localField": "_id",
"foreignField": "bookingId",
"as": "invoice"
}},
{ "$project": {
"checkin" : 1,
"checkout" : 1,
"bookingTotal": {
"$reduce": {
"input": "$invoice",
"initialValue": 0,
"in": {
"$sum": [
{ "$reduce": {
"input": "$$this.invoiceLines",
"initialValue": 0,
"in": { "$sum": [ "$$this.amountTotal", "$$value" ] }
}},
"$$value"
]
}
}
}
}}
])
答案 1 :(得分:1)
您可以在3.4版本中使用$reduce
尝试$concatArrays
。
将amountTotal
视为[[3000, -500], [200], [300, -500]]
。内部$reduce
将amountTotal
转换为[3000, -500, 200, 300, -500]
,后跟外部$reduce
以对金额求和。
{ "$addFields": {
"invoiceTotal":
{
$reduce: {
input: {
$reduce: {
input: "$invoice.invoiceLines",
initialValue: [],
in: { $concatArrays : ["$$value", "$$this.amountTotal"] }
}
},
initialValue: 0,
in: { $add : ["$$value", "$$this"] }
}
}
}}