Има няколко начина за подход към това в зависимост от това кой изходен формат отговаря най-добре на вашите нужди. Основната бележка е, че с "рамката за агрегиране" сама по себе си, вие всъщност не можете да върнете нещо „предадено“ като дата, но можете да получите стойности, които лесно се реконструират в Date
обект при обработка на резултатите във вашия API.
Първият подход е да използвате "Оператори за агрегиране на дати" достъпни за рамката за агрегиране:
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 }
}}
])
Което връща съставен ключ за _id
съдържащ всички стойности, които искате за "дата". Алтернативно, ако винаги в рамките на „час“ просто използвайте частта „минута“ и изчислете действителната дата въз основа на startDate
от вашия избор на диапазон.
Или можете просто да използвате обикновена "Date math", за да получите милисекундите от "epoch", които отново могат да бъдат подавани директно към конструктор на дата.
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 }
}}
])
Във всички случаи това, което винеправите което искате да направите, е да използвате $project
преди действителното прилагане на $group
. Като „етап на тръбопровода“, $project
трябва да "циклира" през всички избрани документи и да "трансформира" съдържанието.
Това отнема време и добавя към общия брой на изпълнението на заявката. Можете просто да кандидатствате към $group
директно, както е показано.
Или ако сте наистина "чисти" относно Date
обектът се връща без последваща обработка, тогава винаги можете да използвате "mapReduce" , тъй като функциите на JavaScript всъщност позволяват преработване като дата, но по-бавно от рамката за агрегиране и разбира се без отговор на курсора:
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 } }
)
Най-добрият ви залог обаче е да използвате агрегиране, тъй като трансформирането на отговора е доста лесно:
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);
})
И след това имате изход за групиране на интервали с реална Date
обекти.