How to get this result with aggregate in mongoDB

2019-06-03 13:51发布

问题:

I have an invoice collection...

{
"_id" : 1,
"items" : [ 
    {
        "_id" : 1,
        "value" : 100,
        "price" : 9500
    }, 
    {
        "_id" : 2,
        "value" : 200,
        "price" : 9500
    }
],
"costs" : [ 
    {
        "_id" : 1,
        "price" : 100
    }, 
    {
        "_id" : 2,
        "price" : 150
    }, 
    {
        "_id" : 3,
        "price" : 250
    }
]}

I get Invoice amount with aggregate...

In other words =>

{$sum : {$multiply :{[$items.value, $items.price]} }} - {$sum : "$costs.price"};

{
  "_id" : 1,
  "amount" : 2849500
}

very thinks...

;-)

回答1:

Mongo 3.4 Version

$map to multiply the item's price & value and $reduce to calculate the sum of item's price & value and $reduce to calculate the sum of cost's price. $subtract values from earlier reduce to get the final amount.

aggregate([{
    $project: {
        _id: 1,
        amount: {
            $subtract: [{
                $reduce: {
                    input: {
                        $map: {
                            input: "$items",
                            as: "item",
                            in: {
                                $multiply: ["$$item.value", "$$item.price"]
                            }
                        }
                    },
                    initialValue: 0,
                    in: {
                        $add: ["$$value", "$$this"]
                    }
                }
            }, {
                $reduce: {
                    input: "$costs.price",
                    initialValue: 0,
                    in: {
                        $add: ["$$value", "$$this"]
                    }
                }
            }]
        }

    }
}])

Mongo 3.x Version

First $project to multiply item's value & price. Next grouping to calculate the sum for both items and costs fields, which will result in one array value for each item and cost field and final project looks at only array value from both arrays with $arrayElemAt to subtract the values from each other.

aggregate(
    [{
        $project: {
            vpItems: {
                $map: {
                    input: "$items",
                    as: "item",
                    in: {
                        $multiply: ["$$item.value", "$$item.price"]
                    }
                }
            },
            costs: '$costs'
        }
    }, {
        $group: {
            _id: '$_id',
            vpItems: {
                $addToSet: {
                    $sum: '$vpItems'
                }
            },
            pCosts: {
                $addToSet: {
                    $sum: '$costs.price'
                }
            }
        }
    }, {
        $project: {
            _id: 1,
            amount: {
                $subtract: [{
                    $arrayElemAt: ["$vpItems", 0]
                }, {
                    $arrayElemAt: ["$pCosts", 0]
                }]
            }
        }
    }])

Mongo 2.6 Version

$unwind items and group to calcualte sum of values returned from multiply the item's price & value and $unwind costs to calculate the sum of item's price & value and project to $subtract values from previous grouping to calculate final amount.

aggregate([{
      $unwind: '$items'
  }, {
      $group: {
          _id: '$_id',
          totalItems: {
              $sum: {
                  $multiply: ["$items.value", "$items.price"]
              }
          },
          costs: {
              $first: '$costs'
          }
      }
  }, {
      $unwind: '$costs'
  }, {
      $group: {
          _id: '$_id',
          totalItems: {
              $first: '$totalItems'
          },
          totalPrice: {
              $sum: '$costs.price'
          }
      }
  }, {
      $project: {
          _id: 1,
          amount: {
              $subtract: ['$totalItems', '$totalPrice']
          }
      }
  }])