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

Mongo-aggregering inden for tidsintervaller

Der er et par måder at gribe dette an på, afhængigt af hvilket outputformat der passer bedst til dine behov. Hovedbemærkningen er, at med "aggregationsramme" selv, kan du faktisk ikke returnere noget "cast" som en dato, men du kan få værdier, der let rekonstrueres til en Date objekt ved behandling af resultater i din API.

Den første tilgang er at bruge "Date Aggregation Operators" tilgængelig for aggregeringsrammen:

db.collection.aggregate([
    { "$match": {
        "time": { "$gte": startDate, "$lt": endDate }
    }},
    { "$group": {
        "_id": {
            "year": { "$year": "$time" },
            "dayOfYear": { "$dayOfYear": "$time" },
            "hour": { "$hour": "$time" },
            "minute": {
                "$subtract": [
                    { "$minute": "$time" },
                    { "$mod": [ { "$minute": "$time" }, 10 ] }
                ]
            }
        },
        "count": { "$sum": 1 }
    }}
])

Som returnerer en sammensat nøgle for _id indeholdende alle de værdier, du ønsker for en "dato". Alternativt, hvis kun inden for en "time" altid, så brug bare "minut"-delen og regn ud den faktiske dato baseret på startDate af dit områdevalg.

Eller du kan bare bruge almindelig "datomatematik" for at få millisekunderne siden "epoke", som igen kan føres direkte til en datokonstruer.

db.collection.aggregate([
    { "$match": {
        "time": { "$gte": startDate, "$lt": endDate }
    }},
    { "$group": {
        "_id": {
            "$subtract": [
               { "$subtract": [ "$time", new Date(0) ] },
               { "$mod": [
                   { "$subtract": [ "$time", new Date(0) ] },
                   1000 * 60 * 10
               ]}
            ]
        },
        "count": { "$sum": 1 }
    }}
])

I alle tilfælde hvad du ikke ønsker at gøre er at bruge $project før du rent faktisk anvender $group . Som et "pipeline-stadium", $project skal "cykle" gennem alle valgte dokumenter og "transformere" indholdet.

Dette tager tid , og føjer til udførelsessummen for forespørgslen. Du kan simpelthen bare ansøge $group direkte som vist.

Eller hvis du virkelig er "ren" omkring en Date objekt, der returneres uden efterbehandling, så kan du altid bruge "mapReduce" , da JavaScript-funktionerne faktisk tillader omformning som en dato, men langsommere end aggregeringsrammen og selvfølgelig uden et markørsvar:

db.collection.mapReduce(
   function() {
       var date = new Date(
           this.time.valueOf() 
           - ( this.time.valueOf() % ( 1000 * 60 * 10 ) )
       );
       emit(date,1);
   },
   function(key,values) {
       return Array.sum(values);
   },
   { "out": { "inline": 1 } }
)

Dit bedste bud er dog at bruge aggregering, da det er ret nemt at transformere svaret:

db.collection.aggregate([
    { "$match": {
        "time": { "$gte": startDate, "$lt": endDate }
    }},
    { "$group": {
        "_id": {
            "year": { "$year": "$time" },
            "dayOfYear": { "$dayOfYear": "$time" },
            "hour": { "$hour": "$time" },
            "minute": {
                "$subtract": [
                    { "$minute": "$time" },
                    { "$mod": [ { "$minute": "$time" }, 10 ] }
                ]
            }
        },
        "count": { "$sum": 1 }
    }}
]).forEach(function(doc) {
    doc._id = new Date(doc._id);
    printjson(doc);
})

Og så har du dit intervalgrupperingsoutput med ægte Date genstande.



  1. Admin panel for Node.js og Mongoose

  2. MongoDB C# Aggregation - slap af -> groupBy

  3. mongoose unikke:sandt ikke arbejde

  4. Find objekter mellem to datoer MongoDB