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

Mongodb agregado en subdocumento en matriz

MapReduce es lento, pero puede manejar conjuntos de datos muy grandes. El marco de agregación, por otro lado, es un poco más rápido, pero tendrá problemas con grandes volúmenes de datos.

El problema con la estructura que se muestra es que necesita "$desenrollar" las matrices para abrir los datos. Esto significa crear un nuevo documento para cada elemento de la matriz y con el marco de agregación que necesita para hacer esto en la memoria. Entonces, si tiene 1000 documentos con 100 elementos de matriz, necesitará crear una secuencia de 100 000 documentos para agruparlos y contarlos.

Es posible que desee considerar ver si hay un diseño de esquema que atenderá mejor sus consultas, pero si desea hacerlo con el marco de agregación, así es como podría hacerlo (con algunos datos de muestra para que todo el script caiga en el shell);

db.so.remove();
db.so.ensureIndex({ "items.sku": 1}, {unique:false});
db.so.insert([
    {
        _id: 42,
        last_modified: ISODate("2012-03-09T20:55:36Z"),
        status: 'active',
        items: [
            { sku: '00e8da9b', qty: 1, item_details: {} },
            { sku: '0ab42f88', qty: 4, item_details: {} },
            { sku: '0ab42f88', qty: 4, item_details: {} },
            { sku: '0ab42f88', qty: 4, item_details: {} },
    ]
    },
    {
        _id: 43,
        last_modified: ISODate("2012-03-09T20:55:36Z"),
        status: 'active',
        items: [
            { sku: '00e8da9b', qty: 1, item_details: {} },
            { sku: '0ab42f88', qty: 4, item_details: {} },
        ]
    },
]);


db.so.runCommand("aggregate", {
    pipeline: [
        {   // optional filter to exclude inactive elements - can be removed    
            // you'll want an index on this if you use it too
            $match: { status: "active" }
        },
        // unwind creates a doc for every array element
        { $unwind: "$items" },
        {
            $group: {
                // group by unique SKU, but you only wanted to count a SKU once per doc id
                _id: { _id: "$_id", sku: "$items.sku" },
            }
        },
        {
            $group: {
                // group by unique SKU, and count them
                _id: { sku:"$_id.sku" },
                doc_count: { $sum: 1 },
            }
        }
    ]
    //,explain:true
})

Tenga en cuenta que $group'd dos veces, porque dijo que un SKU solo puede contarse una vez por documento, por lo que primero debemos clasificar los pares únicos de doc/sku y luego contarlos.

Si desea que el resultado sea un poco diferente (en otras palabras, EXACTAMENTE como en su muestra), podemos $proyectarlos.