sql >> Database >  >> NoSQL >> MongoDB

Mongodb-aggregatie op subdocument in array

MapReduce is traag, maar kan zeer grote datasets aan. Het aggregatieraamwerk is daarentegen iets sneller, maar zal moeite hebben met grote datavolumes.

Het probleem met uw getoonde structuur is dat u de arrays moet "$afwikkelen" om de gegevens te openen. Dit betekent dat er voor elk array-item een ​​nieuw document moet worden gemaakt en met het aggregatieraamwerk moet dit in het geheugen worden gedaan. Dus als je 1000 documenten hebt met 100 array-elementen, moet je een stroom van 100.000 documenten opbouwen om ze te groupBy en te tellen.

Je zou kunnen overwegen om te kijken of er een schemalay-out is die je query's beter zal bedienen, maar als je het met het Aggregation-framework wilt doen, kun je dit als volgt doen (met wat voorbeeldgegevens zodat het hele script in de shell valt);

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

Merk op dat ik twee keer $group'd heb, omdat je zei dat een SKU maar één keer per document kan tellen, dus we moeten eerst de unieke doc/sku-paren uitzoeken en ze dan optellen.

Als u de uitvoer een beetje anders wilt (met andere woorden, PRECIES zoals in uw voorbeeld), kunnen we ze $projecteren.



  1. Een MongoDB-server voorbereiden voor productie

  2. Binning en tabulate (uniek/count) in Mongo

  3. Combinatie van unieke mangoest-nodejs met meerdere kolommen

  4. (MongoDB Compass) opzoeken met let not working