Der er et par måder at gøre dette på.
Den første er med Date Aggregation Operators, som giver dig mulighed for at dissekere "dato"-værdierne i dokumenter. Specifikt for "gruppering" som den primære hensigt:
db.collection.aggregate([
{ "$group": {
"_id": {
"year": { "$year": "$created_at" },
"dayOfYear": { "$dayOfYear": "$created_at" },
"hour": { "$hour": "$created_at" },
"interval": {
"$subtract": [
{ "$minute": "$created_at" },
{ "$mod": [{ "$minute": "$created_at"}, 15] }
]
}
}},
"count": { "$sum": 1 }
}}
])
Den anden måde er ved at bruge et lille trick for, når et datoobjekt trækkes fra (eller anden direkte matematisk operation) fra et andet datoobjekt, så er resultatet en numerisk værdi, der repræsenterer epoketidsstemplet millisekunder mellem de to objekter. Så bare ved at bruge epokedatoen får du repræsentationen af epoke millisekunder. Brug derefter datomatematik til intervallet:
db.collection.aggregate([
{ "$group": {
"_id": {
"$subtract": [
{ "$subtract": [ "$created_at", new Date("1970-01-01") ] },
{ "$mod": [
{ "$subtract": [ "$created_at", new Date("1970-01-01") ] },
1000 * 60 * 15
]}
]
},
"count": { "$sum": 1 }
}}
])
Så det afhænger af, hvilken slags outputformat du ønsker til grupperingsintervallet. Begge repræsenterer grundlæggende det samme og har tilstrækkelige data til at rekonstruere som et "dato"-objekt i din kode.
Du kan sætte alt andet, du ønsker, i "grupperingsoperator"-delen efter grupperingen _id
. Jeg bruger bare det grundlæggende "tælle"-eksempel i stedet for enhver reel udtalelse fra dig selv om, hvad du virkelig vil gøre.
MongoDB 4.x og opefter
Der var nogle tilføjelser til Date Aggregation Operators siden den oprindelige skrivning, men fra MongoDB 4.0 vil der være faktisk "rigtig casting af typer" i modsætning til de grundlæggende matematiske tricks, der udføres her med BSON Date-konvertering.
For eksempel kan vi bruge $toLong
og $toDate
som nye hjælpere her:
db.collection.aggregate([
{ "$group": {
"_id": {
"$toDate": {
"$subtract": [
{ "$toLong": "$created_at" },
{ "$mod": [ { "$toLong": "$created_at" }, 1000 * 60 * 15 ] }
]
}
},
"count": { "$sum": 1 }
}}
])
Det er lidt kortere og kræver ikke, at du definerer en ekstern BSON-dato for "epoke"-værdien som en konstant i definitionen af pipelinen, så den er ret konsistent for alle sprogimplementeringer.
Det er kun to af "hjælper"-metoderne til typekonvertering, som alle knytter sig til $convert
metode, som er en "længere" form for implementeringen, der giver mulighed for tilpasset håndtering på null
eller fejl i konverteringen.
Det er endda muligt med en sådan casting at få Date
oplysninger fra ObjectId
af den primære nøgle, da dette ville være en pålidelig kilde til "oprettelse" dato:
db.collection.aggregate([
{ "$group": {
"_id": {
"$toDate": {
"$subtract": [
{ "$toLong": { "$toDate": "$_id" } },
{ "$mod": [ { "$toLong": { "$toDate": "$_id" } }, 1000 * 60 * 15 ] }
]
}
},
"count": { "$sum": 1 }
}}
])
Så "casting-typer" med denne form for konvertering kan være et ret kraftfuldt værktøj.
Advarsel - ObjectId
værdier er begrænset til præcision til sekund kun for den interne tidsværdi, der udgør en del af deres data, hvilket tillader $toDate
konvertering. Den faktiske indsatte "tid" er højst sandsynligt afhængig af driveren i brug. Hvor præcision er påkrævet, anbefales det stadig at bruge et diskret BSON-datofelt i stedet for at stole på ObjectId
værdier.