MongoDB
 sql >> Datenbank >  >> NoSQL >> MongoDB

Mongodb-Aggregat für Filialdokument im Array

MapReduce ist langsam, kann aber sehr große Datenmengen verarbeiten. Das Aggregation-Framework hingegen ist etwas schneller, wird aber mit großen Datenmengen zu kämpfen haben.

Das Problem mit Ihrer gezeigten Struktur ist, dass Sie die Arrays "$unwind" müssen, um die Daten zu knacken. Dies bedeutet, dass für jedes Array-Element ein neues Dokument erstellt wird, und mit dem Aggregations-Framework muss dies im Speicher erfolgen. Wenn Sie also 1000 Dokumente mit 100 Array-Elementen haben, müssen Sie einen Stream von 100.000 Dokumenten erstellen, um sie zu gruppieren und zu zählen.

Vielleicht möchten Sie prüfen, ob es ein Schema-Layout gibt, das Ihre Abfragen besser verarbeitet, aber wenn Sie es mit dem Aggregation-Framework machen möchten, können Sie es hier tun (mit einigen Beispieldaten, damit das gesamte Skript in die Shell fällt).;

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
})

Beachten Sie, dass ich zweimal $group'd gemacht habe, weil Sie sagten, dass eine SKU nur einmal pro Dokument zählen kann, also müssen wir zuerst die eindeutigen Dokument/Sku-Paare aussortieren und sie dann hochzählen.

Wenn Sie eine etwas andere Ausgabe wünschen (mit anderen Worten, GENAU wie in Ihrem Beispiel), können wir sie $projizieren.