Definición
Cambiado en la versión 5.0.
Devuelve la suma de valores numéricos. $sum ignora los valores no numéricos.
$sum está disponible en estas etapas:
$setWindowFields(Disponible a partir de MongoDB 5.0)
Compatibilidad
Puedes usar $sum para implementaciones alojadas en los siguientes entornos:
- MongoDB Atlas: El servicio totalmente gestionado para implementaciones de MongoDB en la nube
MongoDB Enterprise: La versión basada en suscripción y autogestionada de MongoDB
MongoDB Community: La versión de MongoDB con código fuente disponible, de uso gratuito y autogestionada.
Sintaxis
Cuando se usa como acumulador, $sum tiene esta sintaxis:
{ $sum: <expression> }
Cuando no se usa como acumulador, $sum tiene esta sintaxis:
{ $sum: [ <expression1>, <expression2> ... ] }
Para obtener más información sobre las expresiones, consulta Expresiones.
Comportamiento
Tipo de datos del resultado
Cuando se mezclan los tipos de entrada, $sum promueve el tipo de entrada menor al mayor de los dos. Un tipo se considera mayor cuando representa un rango más amplio de valores. El orden de los tipos numéricos, de menor a mayor, es: entero → largo → doble → decimal
El tipo de entrada mayor también determina el tipo de resultado, a menos que la operación se desborde y salga del rango representado por ese tipo de dato mayor. En casos de desbordamiento, $sum promueve el resultado según el siguiente orden:
Campos no numéricos o no existentes
Si se utiliza en un campo que contiene tanto valores numéricos como no numéricos, $sum ignora los valores no numéricos y devuelve la suma de los valores numéricos.
Si se utiliza en un campo que no existe en ningún documento, $sum devuelve 0 para ese campo.
Si todos los operandos no son numéricos, no son arreglos o contienen valores null, $sum devuelve 0. Para obtener detalles sobre cómo $sum gestiona los arreglos, consulta Operando de arreglo.
Arreglo Operand
En la etapa $group, si la expresión se resuelve en un arreglo, $sum trata el operando como un valor no numérico.
En las otras etapas admitidas:
Con una única expresión como operando, si la expresión se resuelve en un arreglo,
$sumrecorre el arreglo para operar sobre sus elementos numéricos y devolver un único valor.Con una lista de expresiones como su operando, si alguna de las expresiones se resuelve en un arreglo,
$sumno recorre el arreglo sino que lo trata como un valor no numérico.
Por ejemplo, cuando no se utiliza en una etapa $group:
Si el operando
$sumes[ 2, 2 ],$sumsuma los elementos del arreglo y devuelve 4.Si el operando
$sumes[ 2, [ 3, 4 ] ],$sumdevuelve 2 porque trata el arreglo anidado[ 3, 4 ]como un valor no numérico.
Ejemplos
Uso en la etapa $group
Considera una colección sales con los siguientes documentos:
db.sales.insertMany( [ { "_id" : 1, "item" : "abc", "price" : 10, "quantity" : 2, "date" : ISODate("2014-01-01T08:00:00Z") }, { "_id" : 2, "item" : "jkl", "price" : 20, "quantity" : 1, "date" : ISODate("2014-02-03T09:00:00Z") }, { "_id" : 3, "item" : "xyz", "price" : 5, "quantity" : 5, "date" : ISODate("2014-02-03T09:05:00Z") }, { "_id" : 4, "item" : "abc", "price" : 10, "quantity" : 10, "date" : ISODate("2014-02-15T08:00:00Z") }, { "_id" : 5, "item" : "xyz", "price" : 5, "quantity" : 10, "date" : ISODate("2014-02-15T09:05:00Z") } ] )
La siguiente operación agrupa los documentos por día y año del campo date, y luego utiliza $sum para calcular el monto total y el recuento para cada grupo:
db.sales.aggregate( [ { $group: { _id: { day: { $dayOfYear: "$date"}, year: { $year: "$date" } }, totalAmount: { $sum: { $multiply: [ "$price", "$quantity" ] } }, count: { $sum: 1 } } } ] )
La operación arroja:
{ "_id" : { "day" : 46, "year" : 2014 }, "totalAmount" : 150, "count" : 2 } { "_id" : { "day" : 34, "year" : 2014 }, "totalAmount" : 45, "count" : 2 } { "_id" : { "day" : 1, "year" : 2014 }, "totalAmount" : 20, "count" : 1 }
El uso de $sum en un campo inexistente devuelve un valor de 0. La siguiente operación intenta $sum sobre qty:
db.sales.aggregate( [ { $group: { _id: { day: { $dayOfYear: "$date"}, year: { $year: "$date" } }, totalAmount: { $sum: "$qty" }, count: { $sum: 1 } } } ] )
La operación arroja:
{ "_id" : { "day" : 46, "year" : 2014 }, "totalAmount" : 0, "count" : 2 } { "_id" : { "day" : 34, "year" : 2014 }, "totalAmount" : 0, "count" : 2 } { "_id" : { "day" : 1, "year" : 2014 }, "totalAmount" : 0, "count" : 1 }
Puedes usar el acumulador $count en lugar del { $sum : 1 } en la etapa $group.
Uso en la etapa del proyecto
Una colección students contiene los siguientes documentos:
{ "_id": 1, "quizzes": [ 10, 6, 7 ], "labs": [ 5, 8 ], "final": 80, "midterm": 75 } { "_id": 2, "quizzes": [ 9, 10 ], "labs": [ 8, 8 ], "final": 95, "midterm": 80 } { "_id": 3, "quizzes": [ 4, 5, 5 ], "labs": [ 6, 5 ], "final": 78, "midterm": 70 }
El siguiente ejemplo utiliza $sum en la etapa $project para calcular las calificaciones totales de los cuestionarios, las calificaciones totales de los laboratorios y la calificación combinada del examen final y parcial:
db.students.aggregate([ { $project: { quizTotal: { $sum: "$quizzes"}, labTotal: { $sum: "$labs" }, examTotal: { $sum: [ "$final", "$midterm" ] } } } ])
La operación arroja:
{ "_id" : 1, "quizTotal" : 23, "labTotal" : 13, "examTotal" : 155 } { "_id" : 2, "quizTotal" : 19, "labTotal" : 16, "examTotal" : 175 } { "_id" : 3, "quizTotal" : 14, "labTotal" : 11, "examTotal" : 148 }
Uso en la etapa $setWindowFields
Nuevo en la versión 5.0.
Crea una colección de cakeSales que incluya ventas de pasteles en el estado de California (CA) y Washington (WA):
db.cakeSales.insertMany( [ { _id: 0, type: "chocolate", orderDate: new Date("2020-05-18T14:10:30Z"), state: "CA", price: 13, quantity: 120 }, { _id: 1, type: "chocolate", orderDate: new Date("2021-03-20T11:30:05Z"), state: "WA", price: 14, quantity: 140 }, { _id: 2, type: "vanilla", orderDate: new Date("2021-01-11T06:31:15Z"), state: "CA", price: 12, quantity: 145 }, { _id: 3, type: "vanilla", orderDate: new Date("2020-02-08T13:13:23Z"), state: "WA", price: 13, quantity: 104 }, { _id: 4, type: "strawberry", orderDate: new Date("2019-05-18T16:09:01Z"), state: "CA", price: 41, quantity: 162 }, { _id: 5, type: "strawberry", orderDate: new Date("2019-01-08T06:12:03Z"), state: "WA", price: 43, quantity: 134 } ] )
Este ejemplo utiliza $sum en la etapa $setWindowFields para generar la suma de las quantity de pasteles vendidos en cada state:
db.cakeSales.aggregate( [ { $setWindowFields: { partitionBy: "$state", sortBy: { orderDate: 1 }, output: { sumQuantityForState: { $sum: "$quantity", window: { documents: [ "unbounded", "current" ] } } } } } ] )
En el ejemplo:
partitionBy: "$state"particiona los documentos de la colección enstate. Existen particiones paraCAyWA.sortBy: { orderDate: 1 }ordena los documentos de cada partición pororderDateen orden ascendente (1), de modo que elorderDatemás antiguo sea el primero.
outputestablecesumQuantityForStatecomo la suma de los valoresquantityen una ventana de documentos que abarca desde el inicio de la partición (unbounded) hasta el documentocurrent.
En esta salida, el campo sumQuantityForState muestra la suma acumulada de los valores quantity para CA y WA:
{ "_id" : 4, "type" : "strawberry", "orderDate" : ISODate("2019-05-18T16:09:01Z"), "state" : "CA", "price" : 41, "quantity" : 162, "sumQuantityForState" : 162 } { "_id" : 0, "type" : "chocolate", "orderDate" : ISODate("2020-05-18T14:10:30Z"), "state" : "CA", "price" : 13, "quantity" : 120, "sumQuantityForState" : 282 } { "_id" : 2, "type" : "vanilla", "orderDate" : ISODate("2021-01-11T06:31:15Z"), "state" : "CA", "price" : 12, "quantity" : 145, "sumQuantityForState" : 427 } { "_id" : 5, "type" : "strawberry", "orderDate" : ISODate("2019-01-08T06:12:03Z"), "state" : "WA", "price" : 43, "quantity" : 134, "sumQuantityForState" : 134 } { "_id" : 3, "type" : "vanilla", "orderDate" : ISODate("2020-02-08T13:13:23Z"), "state" : "WA", "price" : 13, "quantity" : 104, "sumQuantityForState" : 238 } { "_id" : 1, "type" : "chocolate", "orderDate" : ISODate("2021-03-20T11:30:05Z"), "state" : "WA", "price" : 14, "quantity" : 140, "sumQuantityForState" : 378 }