Istnieje kilka sposobów podejścia do tego, w zależności od tego, który format wyjściowy najlepiej odpowiada Twoim potrzebom. Główna uwaga jest taka, że w przypadku "struktury agregacji" nie można w rzeczywistości zwrócić czegoś "oddanych" jako daty, ale można uzyskać wartości, które można łatwo zrekonstruować na Date
obiektu podczas przetwarzania wyników w Twoim API.
Pierwszym podejściem jest użycie "Operatorów agregacji dat" dostępne w ramach agregacji:
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 }
}}
])
Który zwraca klucz złożony dla _id
zawierające wszystkie żądane wartości dla „daty”. Alternatywnie, jeśli tylko w ciągu "godziny" zawsze użyj części "minuty" i oblicz rzeczywistą datę na podstawie startDate
wybranego zakresu.
Lub możesz po prostu użyć zwykłego „matematyki dat”, aby uzyskać milisekundy od „epoki”, które można ponownie przekazać bezpośrednio do konstruktora dat.
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 }
}}
])
We wszystkich przypadkach czego nie robisz chcesz zrobić, to użyć $project
przed faktycznym zastosowaniem $group
. Jako „etap potoku”, $project
musi „przechodzić” przez wszystkie wybrane dokumenty i „przekształcać” treść.
To zajmuje czas i dodaje do sumy wykonania zapytania. Możesz po prostu zgłosić się do $group
bezpośrednio, jak pokazano.
Lub jeśli naprawdę jesteś „czysty” co do Date
obiekt zwracany bez przetwarzania końcowego, zawsze możesz użyć "mapReduce" , ponieważ funkcje JavaScript faktycznie pozwalają na przekształcenie jako datę, ale wolniej niż struktura agregacji i oczywiście bez odpowiedzi kursora:
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 } }
)
Najlepszym rozwiązaniem jest jednak użycie agregacji, ponieważ przekształcenie odpowiedzi jest dość łatwe:
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);
})
A potem masz wyjście grupowania interwałów z rzeczywistą Date
obiekty.