sql >> Database >  >> NoSQL >> MongoDB

Mongo-aggregatie binnen tijdsintervallen

Er zijn een aantal manieren om dit te benaderen, afhankelijk van welk uitvoerformaat het beste bij uw behoeften past. De belangrijkste opmerking is dat met het "aggregatieraamwerk" zelf, kun je niet echt iets "cast" als een datum retourneren, maar je kunt waarden krijgen die gemakkelijk kunnen worden gereconstrueerd in een Date object bij het verwerken van resultaten in uw API.

De eerste benadering is het gebruik van de "Date Aggregation Operators" beschikbaar voor het aggregatieraamwerk:

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

Die een samengestelde sleutel retourneert voor _id met alle gewenste waarden voor een "datum". Als alternatief, als het altijd maar binnen een "uur" is, gebruik dan gewoon het gedeelte "minuut" en bereken de werkelijke datum op basis van de startDate van uw bereikselectie.

Of u kunt gewoon "Date-wiskunde" gebruiken om de milliseconden sinds "epoch" te krijgen, die opnieuw rechtstreeks aan een datumaannemer kunnen worden doorgegeven.

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

In alle gevallen wat u niet doet wilt doen is gebruik $project voordat u $group daadwerkelijk toepast . Als een "pijplijnfase", $project moet door alle geselecteerde documenten "fietsen" en de inhoud "transformeren".

Dit kost tijd , en wordt toegevoegd aan het uitvoeringstotaal van de query. Je kunt je gewoon aanmelden bij de $group direct zoals is getoond.

Of als je echt "puur" bent over een Date object wordt geretourneerd zonder nabewerking, dan kunt u altijd "mapReduce" , aangezien de JavaScript-functies daadwerkelijk herschikken als een datum toestaan, maar langzamer dan het aggregatieraamwerk en natuurlijk zonder een cursorreactie:

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

Je kunt echter het beste aggregatie gebruiken, omdat het transformeren van de reactie vrij eenvoudig is:

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

En dan heb je de output van je intervalgroepering met echte Date objecten.



  1. Mongo-aggregatie

  2. Mongoose die lege arrays maakt?

  3. Mongoose $ lookup waarbij localField een string is van een ObjectId in ForeignField

  4. Python-object invoegen in mongodb