Existem algumas maneiras de abordar isso, dependendo de qual formato de saída melhor atende às suas necessidades. A observação principal é que com o "estrutura de agregação" em si, você não pode realmente retornar algo "cast" como uma data, mas pode obter valores que são facilmente reconstruídos em uma
Date
objeto ao processar resultados em sua API. A primeira abordagem é usar os "Operadores de agregação de data" disponível para a estrutura de agregação:
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 }
}}
])
Que retorna uma chave composta para
_id
contendo todos os valores que você deseja para uma "data". Alternativamente, se estiver sempre dentro de uma "hora", use a parte "minuto" e calcule a data real com base no startDate
de sua seleção de intervalo. Ou você pode simplesmente usar "Date math" para obter os milissegundos desde "epoch", que podem novamente ser alimentados diretamente a um construtor de datas.
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 }
}}
])
Em todos os casos, o que você não faz quero fazer é usar
$project
antes de aplicar $group
. Como um "estágio de pipeline", $project
deve "circular" por todos os documentos selecionados e "transformar" o conteúdo. Isso leva tempo , e adiciona ao total de execução da consulta. Você pode simplesmente aplicar ao
$group
diretamente como foi mostrado. Ou se você é realmente "puro" sobre uma
Date
objeto sendo retornado sem pós-processamento, você sempre poderá usar "mapReduce" , já que as funções JavaScript realmente permitem a reformulação como uma data, mas mais lenta que a estrutura de agregação e, claro, sem uma resposta do cursor: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 } }
)
Sua melhor aposta é usar a agregação, pois transformar a resposta é bastante fácil:
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);
})
E então você tem sua saída de agrupamento de intervalos com
Date
real objetos.