16

I'm trying to sum some values in an array of documents, with no luck.

This is the Document

db.Cuentas.find().pretty()

{
    "Agno": "2013",
    "Egresos": [
        {
            "Fecha": "28-01-2013",
            "Monto": 150000,
            "Detalle": "Pago Nokia Lumia a @josellop"
        },
        {
            "Fecha": "29-01-2013",
            "Monto": 4000,
            "Detalle": "Cine, Pelicula fome"
        }
    ],
    "Ingresos": [],
    "Mes": "Enero",
    "Monto": 450000,
    "Usuario": "MarioCares"
    "_id": ObjectId(....)
}

So, i need the sum of all the "Monto" in "Egresos" for the "Usuario": "MarioCares". In this example 154000

Using aggregation i use this:

db.Cuentas.aggregate(
    [
        { $match: {"Usuario": "MarioCares"} },
        { $group: 
            {
                _id: null,
                "suma": { $sum: "$Egresos.Monto" }
            }
        }
    ]
)

But i always get

{ "result" : [{ "_id" : null, "suma" : 0 }], "ok" : 1 }

What am i doing wrong ?

P.D. already see this and this

Community
  • 1
  • 1
Mario Cares Cabezas
  • 307
  • 1
  • 2
  • 10
  • 1
    I believe you want to unwind the `Egresos` array first and then group on null and sum – Sammaye Jan 28 '13 at 20:27
  • @Sammaye added {"$unwind": $Egresos } and then i got `ReferenceError: Egresos is not defined` – Mario Cares Cabezas Jan 28 '13 at 20:35
  • You can simplify to use below code in latest versions for summing array values in a single document.`db.Cuentas.aggregate([ {$match: {"Usuario": "MarioCares"} }, {$project: { "suma": {$sum: "$Egresos.Monto" }}} ])` – s7vr Dec 13 '17 at 22:00

3 Answers3

29

As Sammaye indicated, you need to $unwind the Egresos array to duplicate the matched doc per array element so you can $sum over each element:

db.Cuentas.aggregate([
    {$match: {"Usuario": "MarioCares"} }, 
    {$unwind: '$Egresos'}, 
    {$group: {
        _id: null, 
        "suma": {$sum: "$Egresos.Monto" }
    }}
])
JohnnyHK
  • 305,182
  • 66
  • 621
  • 471
11

You can do also by this way. don't need to group just project your fields.

db.Cuentas.aggregate([
    { $match: { "Usuario": "MarioCares" } },
    {
        $project: {
            'MontoSum': { $sum: "$Egresos.Monto" }
        }
    }
])
Imdad
  • 769
  • 1
  • 11
  • 31
Aabid
  • 953
  • 5
  • 23
0

Since mongoDB version 3.4 you can use $reduce to sum array items:

db.collection.aggregate([
  {
    $match: {Usuario: "MarioCares"}
  },
  {
    $project: {
      suma: {
        $reduce: {
          input: "$Egresos",
          initialValue: 0,
          in: {$add: ["$$value", "$$this.Monto"]}
        }
      }
    }
  }
])

Playground example

nimrod serok
  • 14,151
  • 2
  • 11
  • 33