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.