V zásadě chcete dvojité seskupení, ale pomocí operátory agregace dat , pouze příslušné části:
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"
}
}
}}
])
Dvojitá $group
vám poskytne požadovaný formát umístěním výsledků do pole za den. Jeden dokument v ukázce, ale v zásadě získáte výsledky takto:
{
"_id" : {
"customerId" : 123,
"day" : 365
},
"hours" : [
{
"hour" : 10,
"pings" : 2,
"links" : 3
}
]
}
Pokud se vám zdá, že je obtížné se s výsledky operátorů data vypořádat nebo chcete zjednodušený „průchozí“ výsledek pro objekty data, můžete místo toho přetypovat jako časová razítka epoch:
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"
}
}
}}
])
Trik je v tom, když $subtract
jeden objekt data od jiného, dostanete jako výsledek hodnotu "epoch" zpět. V tomto případě použijeme počáteční datum "epochy" k získání celé hodnoty časového razítka a pouze poskytneme "matematiku data" pro opravu časů na požadované intervaly. Takže výsledek:
{
"_id" : {
"customerId" : 123,
"day" : NumberLong("1419984000000")
},
"hours" : [
{
"hour" : NumberLong("1420020000000"),
"pings" : 2,
"links" : 3
}
]
}
Což vám může být chutnější než to, co ve výsledku poskytují operátoři data v závislosti na vašich potřebách.
Můžete také přidat malou zkratku s MongoDB 2.6 prostřednictvím $let
operátor, který vám umožňuje deklarovat "proměnné" pro operace s rozsahem:
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"
}
}
}}
])
Také jsem málem zapomněl zmínit, že vaše hodnoty pro "ping" a "link" jsou ve skutečnosti řetězce, pokud to není překlep. Ale pokud ne, ujistěte se, že je nejprve převedete jako čísla.