Usando el famoso Aggregate en MongoDB

En uno de los sistemas que estoy haciendo, necesitaba sumar ciertos ítems de una colección. En SQL es fácil ya que tenemos algo tan simple como

SELECT SUM(CAMPO) FROM TABLE WHERE CONDICION;

pero en MongoDB se nos complica ya que es schemaless y no siempre puede tener un valor.

Tengo la siguiente estructura (pego tal cual):

> db.Cuentas.find().pretty()
{
        "Agno" : 2013,
        "Egresos" : [
                {
                        "Fecha" : "01-02-2013",
                        "Monto" : 150000,
                        "Detalle" : "Pago Lumia a @Josellop"
                },
                {
                        "Fecha" : "01-02-2013",
                        "Monto" : 45000,
                        "Detalle" : "Diezmo"
                },
                {
                        "Fecha" : "01-02-2013",
                        "Monto" : 20000,
                        "Detalle" : "Pago Celular a papá :D"
                },
                {
                        "Fecha" : "01-02-2013",
                        "Monto" : 4000,
                        "Detalle" : "Sushi Panki rolls con mona"
                },
                {
                        "Fecha" : "01-02-2013",
                        "Monto" : 6000,
                        "Detalle" : "Asado de llamo en Tambo"
                }
        ],
        "Ingresos" : [ ],
        "Mes" : "Febrero",
        "Monto" : 450000,
        "Usuario" : "MarioCares",
        "_id" : ObjectId("510bc53470564b6c03000000")
}

Y como pueden ver, tengo documentos dentro de documentos. En mi caso, necesitaba sumar todos los Monto de Egresos e Ingresos.

Para lograrlo, usamos las famosas sentencias Aggregate de la siguiente forma (en la Shell):

db.Cuentas.aggregate([
    {$match: {"_id" : ObjectId("510bc53470564b6c03000000")} },
    {$unwind: '$Egresos'},
    {$group: {
        _id: null,
        "suma": {$sum: "$Egresos.Monto" }
    }}
])

Y recibimos algo como:

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

Ahora, si queremos llevar eso a PHP, lo hacemos de la siguiente manera:

public function getSumaEgresos($id){
    return $this -> col -> aggregate(
        array('$match' => array('_id' => $id)),
        array('$unwind' => '$Egresos'),
        array('$group' => array(
            "_id" => null,
            "suma" => array( '$sum' => '$Egresos.Monto' )
        ) )
    );
}

Y para leer únicamente la suma, lo hacemos así:

$sumaEgresos = $tmp -> getSumaEgresos(new MongoID($id));
$sumaEgresos = $sumaEgresos["result"];
$sumaEgresos = (empty($sumaEgresos) ? 0 : $sumaEgresos[0]["suma"]);
echo $sumaEgresos;

Ojo que cuando lo subí a OpenShift …😯 se muricio :C dando el siguiente mensaje

Fatal error: Call to undefined method MongoCollection::aggregate() in /var/lib/openshift/

Lo cual me pareció raro, siendo que estaba ocupando las funciones de Mongo sin problemas… El tema, es que el driver que ocupan ellos (OpenShift) está des.actualizado. Cuando crean una App en php, el driver a ocupar siempre es (al menos por ahora) el 1.2.6 y es por eso que la función no la reconoce, porque en esa versión no venía incluida😀

De modo que, al menos por ahora, no queda otra que esperar a que actualicen el driver.

Acerca de MaritoCares

Ingeniero Informático. Con tendencias a la programación en [C#, VB].NET, Java(Web principalmente...), PHP, JavaScript, algo mínimo de [ruby, python], y el clásico C.
Esta entrada fue publicada en MongoDB, php, Tips. Guarda el enlace permanente.

5 respuestas a Usando el famoso Aggregate en MongoDB

  1. Obux dijo:

    Si a veces mongo nos da tarea🙂 me estoy metiendo mucho e mongo y algo que me saca de onda es una forma de optimizar las consultas a través del _id y no tener que poner el hash completo..

    • MaritoCares dijo:

      Hola !

      Tengo entendido que lo mejor es consultar por los _id de cada documento.

      Ya que Mongo internamente tiene pareados los _id con el documento, haciendo más rápida la consulta.

      Otra forma es agregar el campo que quieras usar a modo de índice, que básicamente es lo mismo que usando los _id🙂

  2. Obux dijo:

    Por cierto estas en mi blogroll para seguir tus andanzas colega.. saludos

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s