Można to zrobić na kilka sposobów.
Pierwszym z nich są operatory agregacji dat, które pozwalają analizować wartości „dat” w dokumentach. Specjalnie dla „grupowania” jako głównego celu:
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 }
}}
])
Drugi sposób polega na zastosowaniu małej sztuczki polegającej na odjęciu obiektu daty (lub innej bezpośredniej operacji matematycznej) od innego obiektu daty, a wynikiem jest wartość liczbowa reprezentująca milisekundy znacznika czasu epoki między tymi dwoma obiektami. Tak więc po prostu używając daty epoki, otrzymujesz reprezentację epoki w milisekundach. Następnie użyj matematyki daty jako przedziału:
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 }
}}
])
Zależy to więc od rodzaju formatu wyjściowego dla przedziału grupowania. Oba w zasadzie reprezentują to samo i mają wystarczającą ilość danych do rekonstrukcji jako obiektu „daty” w kodzie.
Możesz umieścić cokolwiek chcesz w części „operator grupowania” po grupowaniu _id
. Po prostu używam podstawowego przykładu "liczenia" zamiast jakiegokolwiek prawdziwego stwierdzenia od siebie, co naprawdę chcesz zrobić.
MongoDB 4.x i nowsze
Było kilka dodatków do operatorów agregacji danych od czasu pierwotnego napisania, ale od MongoDB 4.0 będzie rzeczywiste „rzeczywiste rzutowanie typów”, w przeciwieństwie do podstawowych sztuczek matematycznych wykonywanych tutaj z konwersją daty BSON.
Na przykład możemy użyć $toLong
i $toDate
jako nowi pomocnicy tutaj:
db.collection.aggregate([
{ "$group": {
"_id": {
"$toDate": {
"$subtract": [
{ "$toLong": "$created_at" },
{ "$mod": [ { "$toLong": "$created_at" }, 1000 * 60 * 15 ] }
]
}
},
"count": { "$sum": 1 }
}}
])
Jest to nieco krótsze i nie wymaga definiowania zewnętrznej daty BSON dla wartości „epoki” jako stałej w definiowaniu potoku, więc jest dość spójne dla wszystkich implementacji językowych.
To tylko dwie z "pomocniczych" metod konwersji typów, które są powiązane z $convert
metoda, która jest "dłuższą" formą implementacji pozwalającą na niestandardową obsługę na null
lub błąd w konwersji.
Przy takim rzutowaniu można nawet uzyskać Date
informacje z ObjectId
klucza podstawowego, ponieważ byłoby to wiarygodne źródło daty „utworzenia”:
db.collection.aggregate([
{ "$group": {
"_id": {
"$toDate": {
"$subtract": [
{ "$toLong": { "$toDate": "$_id" } },
{ "$mod": [ { "$toLong": { "$toDate": "$_id" } }, 1000 * 60 * 15 ] }
]
}
},
"count": { "$sum": 1 }
}}
])
Tak więc „typy rzutowania” z tego rodzaju konwersją mogą być dość potężnym narzędziem.
Ostrzeżenie - ObjectId
wartości są ograniczone do dokładności do sekundy tylko dla wewnętrznej wartości czasu, która stanowi część ich danych, umożliwiającą $toDate
konwersja. Faktyczny wstawiony „czas” najprawdopodobniej zależy od używanego sterownika. Gdzie precyzja jest wymagane, nadal zaleca się używanie dyskretnego pola daty BSON zamiast polegania na ObjectId
wartości.