Existuje několik způsobů, jak toho dosáhnout v závislosti na tom, který výstupní formát nejlépe vyhovuje vašim potřebám. Hlavní poznámka je, že s "rámcem agregace" ve skutečnosti nemůžete vrátit něco "obsazeno" jako datum, ale můžete získat hodnoty, které lze snadno rekonstruovat do Date
objekt při zpracování výsledků ve vašem rozhraní API.
Prvním přístupem je použití "Date Aggregation Operators" dostupné pro agregační rámec:
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 }
}}
])
Což vrací složený klíč pro _id
obsahující všechny hodnoty, které chcete pro "datum". Alternativně, pokud vždy jen do „hodiny“, pak stačí použít část „minuta“ a zjistit skutečné datum na základě startDate
z vašeho výběru rozsahu.
Nebo můžete jednoduše použít prostý "Date math" a získat milisekundy od "epochy", které lze opět přenést přímo do data constructor.
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 }
}}
])
Ve všech případech to, co neděláte chci udělat, je použít $project
před skutečným použitím $group
. Jako "projektová fáze", $project
musí „cyklovat“ všemi vybranými dokumenty a „transformovat“ obsah.
To zabere čas a přidá k celkovému počtu provedení dotazu. Můžete se jednoduše přihlásit do $group
přímo, jak bylo ukázáno.
Nebo pokud jste opravdu "čistí" ohledně Date
objekt se vrací bez následného zpracování, pak můžete vždy použít "mapReduce" , protože funkce JavaScriptu ve skutečnosti umožňují přetypování jako datum, ale pomaleji než agregační rámec a samozřejmě bez odezvy kurzoru:
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 } }
)
Nejlepším řešením je však použití agregace, protože transformace odpovědi je docela snadná:
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 pak máte výstup seskupení intervalů se skutečným Date
objektů.