sql >> Database >  >> NoSQL >> MongoDB

Mongodb - bevraag de totalen van vandaag, de totalen van de week en de totalen van de maand in één zoekopdracht

Dit is meer een kwestie van hoe u verwacht dat de uitvoer eruit zal zien, aangezien elk geaggregeerd resultaat in wezen op het laagste niveau moet worden gegroepeerd en vervolgens geleidelijk moet worden gegroepeerd op hogere "korrels" totdat het grootste niveau ("maand") is bereikt. Dit soort gegevens houdt uiteindelijk in gegroepeerd op "maand", tenzij u ze anders opsplitst.

In wezen geleidelijk $group :

db.collection.aggregate([
    // First total per day. Rounding dates with math here
    { "$group": {
        "_id": {
            "$add": [
                { "$subtract": [
                    { "$subtract": [ "$createdAt", new Date(0) ] },
                    { "$mod": [
                        { "$subtract": [ "$createdAt", new Date(0) ] },
                        1000 * 60 * 60 * 24
                    ]}                        
                ]},
                new Date(0)
            ]
        },
        "week": { "$first": { "$week": "$createdAt" } },
        "month": { "$first": { "$month": "$createdAt" } },
        "total": { "$sum": "$num" }
    }},

    // Then group by week
    { "$group": {
        "_id": "$week",
        "month": { "$first": "$month" },
        "days": {
            "$push": {
                "day": "$_id",
                "total": "$total"
            }
        },
        "total": { "$sum": "$total" }
    }},

    // Then group by month
    { "$group": {
        "_id": "$month",
        "weeks": {
            "$push": {
                "week": "$_id",
                "total": "$total",
                "days": "$days"
            }
        },
        "total": { "$sum": "$total" }
    }}
])

Dus elk niveau na het eerste dat per dag wordt opgeteld, wordt vervolgens progressief in de array-inhoud geduwd voor zijn "afgeronde" waarde en de totalen worden vervolgens ook op dat niveau opgeteld.

Als u een vlakkere uitvoer wilt met één record per dag met daarin zowel de wekelijkse en maandelijkse totalen als het dagtotaal, voeg dan gewoon twee $unwind toe verklaringen aan het einde van de pijplijn:

{ "$unwind": "$weeks" },
{ "$unwind": "$weeks.days" }

En optioneel $project de "gestippelde" velden naar iets platter en leesbaarder als het moet.

Als u hiermee "jaren" overspant, neem dan een dergelijke bewerking op in de groeperingssleutel ten minste vanaf het "week"-niveau, zodat u onmogelijk gegevens van verschillende jaren combineert en ze worden gescheiden.

Het is ook mijn eigen algemene voorkeur om de "date math" te gebruiken benadering bij het afronden van datums omdat het een Date oplevert object, maar zoals wordt gebruikt op de andere niveaus dan "dag", kunt u gewoon afwisselend de operators voor datumaggregatie in plaats daarvan.

Geen behoefte aan mapReduce omdat dit redelijk intuïtief is en er een eindig aantal dagen in een maand is, betekent dit dat de BSON-limiet bij het nesten van arrays in de inhoud tijdens het aggregeren niet wordt verbroken.




  1. Geospatiale ondersteuning in MongoDB

  2. Eindeloze herstellende staat van secundair

  3. MongoDb PHP-stuurprogramma installatieprobleem op wamp

  4. Mongoose (mongodb) batch-insert?