Se for apenas obter as coisas em intervalos de 10 segundos, você pode fazer um pouco de matemática e executar isso através do agregado:
db.collection.aggregate([
{ "$group": {
"_id": {
"year": { "$year": "$created_at" },
"month":{ "$month": "$created_at" },
"day": { "$dayOfMonth": "$created_at" },
"hour": { "$hour": "$created_at" },
"minute": { "$minute": "$created_at" },
"second": { "$subtract": [
{ "$second": "$created_at" },
{ "$mod": [
{ "$second": "$created_at" },
10
]}
]}
},
"count": { "$sum" : 1 }
}}
])
Então, isso divide as coisas em intervalos de 10 segundos em um minuto, onde ocorrem com um pouco de matemática mod 10.
Eu acho que é razoável, e seria o corredor mais rápido, pois usa agregado. Se você realmente precisar que sua sequência, conforme mostrado, seja uma execução de 10 segundos a partir de um tempo inicialmente combinado, você pode fazer o processo com mapReduce:
Primeiro um mapeador:
var mapper = function () {
if ( this.created_at.getTime() > ( last_date + 10000 ) ) {
if ( last_date == 0 ) {
last_date = this.created_at.getTime();
} else {
last_date += 10000;
}
}
emit(
{
start: new Date( last_date ),
end: new Date( last_date + 10000 )
},
this.created_at
);
}
Então isso vai emitir datas dentro de um intervalo de 10 segundos, começando com a primeira data e aumentando o intervalo cada vez que algo for encontrado fora do intervalo
Agora você precisa de um redutor:
var reducer = function (key, values) {
return values.length;
};
Muito simples. Apenas retorne o comprimento do array passado.
Como mapReduce funciona do jeito que funciona, qualquer coisa que não tenha mais de um valor não é passada para o redutor, então limpe isso com finalize:
var finalize = function (key, value) {
if ( typeof(value) == "object" ) {
value = 1;
}
return value;
};
Em seguida, basta executá-lo para obter os resultados. Observe a seção "scope" que passa uma variável global a ser usada no mapeador:
db.collection.mapReduce(
mapper,
reducer,
{
"out": { "inline": 1 },
"scope": { "last_date": 0 },
"finalize": finalize
}
)
Cada abordagem provavelmente dará resultados ligeiramente diferentes, mas esse é o ponto. Depende de qual você realmente quer usar.
Considerando seu comentário, você pode "inspecionar" a saída de qualquer instrução e "preencher as lacunas" programaticamente. Eu geralmente prefiro essa opção, mas não é o meu programa e não sei o tamanho da série que você está tentando recuperar dessa consulta.
No lado do servidor, você pode corrigir o "mapeador" para fazer algo como isto:
var mapper = function () {
if ( this.created_at.getTime() > ( last_date + 10000 ) ) {
if ( last_date == 0 ) {
last_date = this.created_at.getTime();
} else {
// Patching for empty blocks
var times = Math.floor(
( this.created_at.getTime() - last_date ) / 10000
);
if ( times > 1 ) {
for ( var i=1; i < times; i++ ) {
last_date += 10000;
emit(
{
start: new Date( last_date ),
end: new Date( last_date + 10000 )
},
0
);
}
}
// End patch
last_date += 10000;
}
}
emit(
{
start: new Date( last_date ),
end: new Date( last_date + 10000 )
},
this.created_at
);
}