sql >> Database teknologi >  >> NoSQL >> MongoDB

Mongodb-aggregat på underdokument i array

MapReduce er langsom, men den kan håndtere meget store datasæt. Aggregeringsrammen er på den anden side lidt hurtigere, men vil kæmpe med store datamængder.

Problemet med din viste struktur er, at du skal "$afvikle" arrays for at åbne dataene. Det betyder, at der oprettes et nyt dokument for hvert array-element og med den aggregeringsramme, det skal gøre dette i hukommelsen. Så hvis du har 1000 dokumenter med 100 array-elementer, skal du bygge en strøm på 100.000 dokumenter for at gruppere efter og tælle dem.

Du vil måske overveje at se, om der er et skemalayout, der serverer dine forespørgsler bedre, men hvis du vil gøre det med Aggregation-rammen, kan du gøre det her (med nogle eksempeldata, så hele scriptet falder ind i skallen);

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

Bemærk, at jeg har $group'd to gange, fordi du sagde, at en SKU kun kan tælle én gang pr. dokument, så vi skal først sortere de unikke doc/sku-par og derefter tælle dem op.

Hvis du vil have outputtet lidt anderledes (med andre ord NØJLIGT som i dit eksempel), kan vi $projicere dem.



  1. Tilfældig sorteringsrækkefølge

  2. mongodb mislykkedes:fejl ved forbindelse til db-server:ingen tilgængelige servere

  3. Mongoengine, henter kun noget af et MapField

  4. Får en fejl ved indsættelse i en meteorsamling