MongoDB
 sql >> Base de Dados >  >> NoSQL >> MongoDB

Agregação do Mongodb no subdocumento na matriz


O MapReduce é lento, mas pode lidar com conjuntos de dados muito grandes. A estrutura de agregação, por outro lado, é um pouco mais rápida, mas terá dificuldades com grandes volumes de dados.

O problema com sua estrutura mostrada é que você precisa "$desenrolar" os arrays para abrir os dados. Isso significa criar um novo documento para cada item do array e, com a estrutura de agregação, ele precisa fazer isso na memória. Portanto, se você tiver 1.000 documentos com 100 elementos de matriz, será necessário criar um fluxo de 100.000 documentos para agrupar por e contá-los.

Você pode querer considerar ver se há um layout de esquema que servirá melhor suas consultas, mas se você quiser fazer isso com a estrutura de agregação, veja como você pode fazer isso (com alguns dados de amostra para que todo o script caia no 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
})

Observe que eu $group'd duas vezes, porque você disse que um SKU só pode contar uma vez por documento, então precisamos primeiro classificar os pares únicos doc/sku e depois contá-los.

Se você quiser que a saída seja um pouco diferente (em outras palavras, EXATAMENTE como em sua amostra), podemos $projetá-los.