To, czego zasadniczo potrzebujesz, to podwójne grupowanie, ale nie odzyskujesz całego obiektu daty za pomocą operatory agregacji dat , tylko odpowiednie części:
db.collection.aggregate([
{ "$group": {
"_id": {
"customerId": "$customerId",
"day": { "$dayOfYear": "$startTime" },
"hour": { "$hour": "$startTime" }
},
"pings": { "$sum": "$ping" },
"links": { "$sum": "$link" }
}},
{ "$group": {
"_id": {
"customerId": "$_id.customerId",
"day": "$_id.day"
},
"hours": {
"$push": {
"hour": "$_id.hour",
"pings": "$pings",
"links": "$links"
}
}
}}
])
Podwójne $group
daje żądany format, umieszczając wyniki w tablicy na dzień. Pojedynczy dokument w próbce, ale zasadniczo otrzymujesz takie wyniki:
{
"_id" : {
"customerId" : 123,
"day" : 365
},
"hours" : [
{
"hour" : 10,
"pings" : 2,
"links" : 3
}
]
}
Jeśli okaże się, że wyniki operatorów dat są zbyt trudne do opanowania lub chcesz uzyskać uproszczony wynik „przekazywania” dla obiektów daty, możesz zamiast tego rzutować jako znaczniki czasu epoki:
db.collection.aggregate([
{ "$group": {
"_id": {
"customerId": "$customerId",
"day": {
"$subtract": [
{ "$subtract": [ "$startTime", new Date("1970-01-01") ] },
{
"$mod": [
{ "$subtract": [ "$startTime", new Date("1970-01-01") ] },
1000*60*60*24
]
}
]
},
"hour": {
"$subtract": [
{ "$subtract": [ "$startTime", new Date("1970-01-01") ] },
{
"$mod": [
{ "$subtract": [ "$startTime", new Date("1970-01-01") ] },
1000*60*60
]
}
]
}
},
"pings": { "$sum": "$ping" },
"links": { "$sum": "$link" }
}},
{ "$group": {
"_id": {
"customerId": "$_id.customerId",
"day": "$_id.day"
},
"hours": {
"$push": {
"hour": "$_id.hour",
"pings": "$pings",
"links": "$links"
}
}
}}
])
Sztuczka polega na tym, że $subtract
jeden obiekt daty z innego otrzymujesz w rezultacie wartość "epoka". W tym przypadku używamy daty rozpoczęcia "epoki", aby uzyskać całą wartość znacznika czasu i po prostu dostarczamy "matematykę daty", aby poprawić czasy do wymaganych interwałów. Wynik:
{
"_id" : {
"customerId" : 123,
"day" : NumberLong("1419984000000")
},
"hours" : [
{
"hour" : NumberLong("1420020000000"),
"pings" : 2,
"links" : 3
}
]
}
Co może być dla Ciebie przyjemniejsze niż to, co zapewniają operatorzy dat w zależności od Twoich potrzeb.
Możesz również dodać krótki skrót do MongoDB 2.6 za pośrednictwem $let
operator, który pozwala deklarować "zmienne" dla operacji w zakresie:
db.event.aggregate([
{ "$group": {
"_id": {
"$let": {
"vars": {
"date": { "$subtract": [ "$startTime", new Date("1970-01-01") ] },
"day": 1000*60*60*24,
"hour": 1000*60*60
},
"in": {
"customerId": "$customerId",
"day": {
"$subtract": [
"$$date",
{ "$mod": [ "$$date", "$$day" ] }
]
},
"hour": {
"$subtract": [
"$$date",
{ "$mod": [ "$$date", "$$hour" ] }
]
}
}
}
},
"pings": { "$sum": "$ping" },
"links": { "$sum": "$link" }
}},
{ "$group": {
"_id": {
"customerId": "$_id.customerId",
"day": "$_id.day"
},
"hours": {
"$push": {
"hour": "$_id.hour",
"pings": "$pings",
"links": "$links"
}
}
}}
])
Prawie zapomniałem też wspomnieć, że twoje wartości dla "ping" i "link" są w rzeczywistości ciągami, chyba że jest to literówka. Ale jeśli nie, upewnij się, że najpierw przekonwertujesz je jako liczby.