Er zijn een aantal manieren om dit te doen.
De eerste is met Date Aggregation Operators, waarmee u de "datum"-waarden in documenten kunt ontleden. Specifiek voor "groeperen" als de primaire bedoeling:
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 }
}}
])
De tweede manier is door een klein trucje te gebruiken:wanneer een datumobject wordt afgetrokken (of een andere directe wiskundige bewerking) van een ander datumobject, is het resultaat een numerieke waarde die de tijdstempel van het tijdperk in milliseconden tussen de twee objecten weergeeft. Dus als u alleen de epochedatum gebruikt, krijgt u de epoche-millisecondenweergave. Gebruik dan datumberekening voor het interval:
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 }
}}
])
Het hangt dus af van wat voor soort uitvoerformaat u wilt voor het groeperingsinterval. Beide vertegenwoordigen in wezen hetzelfde en hebben voldoende gegevens om te reconstrueren als een "datum" -object in uw code.
U kunt alles wat u maar wilt in het gedeelte "groeperingsoperator" plaatsen na de groepering _id
. Ik gebruik gewoon het eenvoudige "tel"-voorbeeld in plaats van een echte verklaring van jezelf over wat je echt wilt doen.
MongoDB 4.x en hoger
Er waren enkele toevoegingen aan Date Aggregation Operators sinds het oorspronkelijke schrijven, maar vanaf MongoDB 4.0 zal er daadwerkelijk "echte typen van typen" zijn in tegenstelling tot de elementaire wiskundige trucs die hier worden gedaan met BSON-datumconversie.
We kunnen bijvoorbeeld $toLong
. gebruiken en $toDate
als nieuwe helpers hier:
db.collection.aggregate([
{ "$group": {
"_id": {
"$toDate": {
"$subtract": [
{ "$toLong": "$created_at" },
{ "$mod": [ { "$toLong": "$created_at" }, 1000 * 60 * 15 ] }
]
}
},
"count": { "$sum": 1 }
}}
])
Dat is iets korter en vereist geen het definiëren van een externe BSON-datum voor de "epoch" -waarde als een constante bij het definiëren van de pijplijn, dus het is redelijk consistent voor alle taalimplementaties.
Dit zijn slechts twee van de "helper"-methoden voor typeconversie die allemaal terug te voeren zijn op de $convert
methode, wat een "langere" vorm van de implementatie is die aangepaste verwerking op null
mogelijk maakt of fout in conversie.
Met zo'n casting is het zelfs mogelijk om de Date
. te krijgen informatie van de ObjectId
van de primaire sleutel, aangezien dit een betrouwbare bron van de "aanmaak"-datum zou zijn:
db.collection.aggregate([
{ "$group": {
"_id": {
"$toDate": {
"$subtract": [
{ "$toLong": { "$toDate": "$_id" } },
{ "$mod": [ { "$toLong": { "$toDate": "$_id" } }, 1000 * 60 * 15 ] }
]
}
},
"count": { "$sum": 1 }
}}
])
Dus "casting-types" met dit soort conversie kunnen een behoorlijk krachtig hulpmiddel zijn.
Waarschuwing - ObjectId
waarden zijn beperkt tot precisie tot de seconde alleen voor de interne tijdwaarde die deel uitmaakt van hun gegevens waardoor de $toDate
conversie. De daadwerkelijk ingevoerde "tijd" is hoogstwaarschijnlijk afhankelijk van de gebruikte driver. Waar precisie is vereist, wordt het nog steeds aanbevolen om een afzonderlijk BSON-datumveld te gebruiken in plaats van te vertrouwen op ObjectId
waarden.