sql >> Base de Datos >  >> NoSQL >> MongoDB

Mejoras en el marco de agregación de MongoDB 2.6

Esta es una publicación invitada de Vlad Mihalcea. Vlad es un arquitecto de software apasionado por la integración de software, la alta escalabilidad y los desafíos de concurrencia. Aquí hay un enlace a la publicación original.

MongoDB está evolucionando rápidamente. La versión 2.2 introdujo el marco de agregación como una alternativa al modelo de consulta Map-Reduce. La generación de informes agregados es un requisito recurrente para los sistemas empresariales y MongoDB brilla en este sentido. Si es nuevo en esto, es posible que desee consultar esta introducción al marco de agregación o el ajuste de rendimiento y las guías de modelado de datos.

Reutilicemos el modelo de datos que introduje por primera vez mientras demostraba las capacidades de inserción ultrarrápidas de MongoDB:

{
        "_id" : ObjectId("5298a5a03b3f4220588fe57c"),
        "created_on" : ISODate("2012-04-22T01:09:53Z"),
        "value" : 0.1647851116706831
}

Mejoras de agregación de MongoDB 2.6

En la versión 2.4, si ejecuto la siguiente consulta de agregación:

db.randomData.aggregate( [
{
    $match: {
        "created_on" : {
            $gte : new Date(Date.UTC(2012, 0, 1)),
            $lte : new Date(Date.UTC(2012, 0, 10))
        }
    }
},
{
    $group: {
        _id : {
            "minute" : {
                $minute : "$created_on"
            }
        },
        "values": {
            $addToSet: "$value"
        }
    }
}]);

Alcancé el límite de resultado de agregación de 16 MB:

{
    "errmsg" : "exception: aggregation result exceeds maximum document size (16MB)",
    "code" : 16389,
    "ok" : 0
}

Los documentos de MongoDB tienen un límite de 16 MB y, antes de la versión 2.6, el resultado de la agregación era un documento BSON. La versión 2.6 lo reemplazó con un cursor.

Ejecutar la misma consulta en 2.6 arroja el siguiente resultado:

db.randomData.aggregate( [
{
    $match: {
        "created_on" : {
            $gte : new Date(Date.UTC(2012, 0, 1)),
            $lte : new Date(Date.UTC(2012, 0, 10))
        }
    }
},
{
    $group: {
        _id : {
            "minute" : {
                $minute : "$created_on"
            }
        },
        "values": {
            $addToSet: "$value"
        }
    }
}])
.objsLeftInBatch();
14

Usé el método objsLeftInBatch basado en el cursor para probar el tipo de resultado de agregación y la limitación de 16 MB ya no se aplica al resultado general. Los resultados internos del cursor son documentos BSON regulares, por lo tanto, todavía están limitados a 16 MB, pero esto es mucho más manejable que el límite de resultados general anterior.

La versión 2.6 también aborda las restricciones de memoria de agregación. Un escaneo completo de la colección como:

db.randomData.aggregate( [
{
    $group: {
        _id : {
            "minute" : {
                $minute : "$created_on"
            }
        },
        "values": {
            $addToSet: "$value"
        }
    }
}])
.objsLeftInBatch();

puede terminar con el siguiente error:

{
    "errmsg" : "exception: Exceeded memory limit for $group, but didn't allow external sort. Pass allowDiskUse:true to opt in.",
    "code" : 16945,
    "ok" : 0
}

Entonces, ahora podemos realizar grandes operaciones de clasificación usando el parámetro allowDiskUse:

db.randomData.aggregate( [
{
    $group: {
        _id : {
            "minute" : {
                $minute : "$created_on"
            }
        },
        "values": {
            $addToSet: "$value"
        }
    }
}]
,
{
    allowDiskUse : true
})
.objsLeftInBatch();

La versión 2.6 nos permite guardar el resultado de la agregación en una colección diferente usando la etapa $out agregada recientemente.

db.randomData.aggregate( [
{
    $match: {
        "created_on" : {
            $gte : new Date(Date.UTC(2012, 0, 1)),
            $lte : new Date(Date.UTC(2012, 0, 10))
        }
    }
},
{
    $group: {
        _id : {
            "minute" : {
                $minute : "$created_on"
            }
        },
        "values": {
            $addToSet: "$value"
        }
    }
},
{
    $out : "randomAggregates"
}
]);
db.randomAggregates.count();
60

Se han agregado nuevos operadores como let, map, cond, por nombrar algunos.

El siguiente ejemplo agregará AM o PM a la información de tiempo de cada entrada de evento específico.

var dataSet = db.randomData.aggregate( [
{
    $match: {
        "created_on" : {
            $gte : new Date(Date.UTC(2012, 0, 1)),
            $lte : new Date(Date.UTC(2012, 0, 2))
        }
    }
},
{
    $project: {
        "clock" : {
            $let: {
                vars: {
                    "hour": {
                        $substr: ["$created_on", 11, -1]
                    },
                    "am_pm": { $cond: { if: { $lt: [ {$hour : "$created_on" }, 12 ] } , then: 'AM',else: 'PM'} }
                },
                in: { $concat: [ "$$hour", " ", "$$am_pm"] }
            }
        }
    }
},
{
    $limit : 10
}
]);
dataSet.forEach(function(document)  {
    printjson(document);
});

Resultando en:

"clock" : "16:07:14 PM"
"clock" : "22:14:42 PM"
"clock" : "21:46:12 PM"
"clock" : "03:35:00 AM"
"clock" : "04:14:20 AM"
"clock" : "03:41:39 AM"
"clock" : "17:08:35 PM"
"clock" : "18:44:02 PM"
"clock" : "19:36:07 PM"
"clock" : "07:37:55 AM"

Conclusión

La versión 2.6 de MongoDB viene con muchas otras mejoras, como operaciones masivas o intersección de índices. MongoDB está en constante evolución y ofrece una alternativa viable para el almacenamiento basado en documentos. A tal ritmo de desarrollo, no es de extrañar que haya sido nombrada base de datos del año 2013.