Det finns ett par sätt att närma sig detta beroende på vilket utdataformat som bäst passar dina behov. Den viktigaste anmärkningen är att med "aggregationsramverket" i sig kan du faktiskt inte returnera något "cast" som ett datum, men du kan få värden som enkelt kan rekonstrueras till ett Date
objekt när du bearbetar resultat i ditt API.
Den första metoden är att använda "Date Aggregation Operators" tillgänglig för aggregeringsramverket:
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 returnerar en sammansatt nyckel för _id
som innehåller alla värden du vill ha för ett "datum". Alternativt, om bara inom en "timme" alltid, använd bara "minut"-delen och räkna ut det faktiska datumet baserat på startDate
av ditt urval.
Eller så kan du bara använda vanlig "Date math" för att få millisekunderna sedan "epok" som återigen kan matas direkt till en datumkonstruktör.
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 alla fall vad du inte vill göra är att använda $project
innan du faktiskt tillämpar $group
. Som ett "pipeline stadium", $project
måste "cirkulera" genom alla valda dokument och "omvandla" innehållet.
Detta tar tid , och läggs till exekveringssumman för frågan. Du kan helt enkelt ansöka till $group
direkt som visats.
Eller om du verkligen är "ren" om ett Date
objekt som returneras utan efterbearbetning, då kan du alltid använda "mapReduce" , eftersom JavaScript-funktionerna faktiskt tillåter omarbetning som ett datum, men långsammare än aggregeringsramverket och naturligtvis utan 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 } }
)
Det bästa är dock att använda aggregering, eftersom det är ganska enkelt att omvandla 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);
})
Och sedan har du din intervallgrupperingsutdata med riktig Date
objekt.