S'il s'agit simplement d'obtenir des choses dans des intervalles de 10 secondes, vous pouvez faire un peu de calcul et exécuter ceci dans l'agrégat :
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 }
}}
])
Donc, cela décompose les choses en intervalles de 10 secondes dans une minute où elles se produisent avec un peu de maths mod 10.
Je pense que c'est raisonnable et que ce serait le coureur le plus rapide car il utilise des agrégats. Si vous avez vraiment besoin que votre séquence, comme indiqué, dure 10 secondes à partir d'un temps initial correspondant, vous pouvez effectuer le processus avec mapReduce :
D'abord un mappeur :
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
);
}
Cela va donc émettre des dates dans un intervalle de 10 secondes, en commençant par la première date, puis en augmentant l'intervalle chaque fois que quelque chose est trouvé hors plage
Maintenant, vous avez besoin d'un réducteur :
var reducer = function (key, values) {
return values.length;
};
Très simple. Renvoie simplement la longueur du tableau transmis.
Étant donné que mapReduce fonctionne comme il le fait, tout ce qui n'a pas plus d'une valeur n'est pas transmis au réducteur, alors nettoyez cela avec finalize :
var finalize = function (key, value) {
if ( typeof(value) == "object" ) {
value = 1;
}
return value;
};
Ensuite, lancez-le pour obtenir les résultats. Notez la section "scope" qui passe une variable globale à utiliser dans le mappeur :
db.collection.mapReduce(
mapper,
reducer,
{
"out": { "inline": 1 },
"scope": { "last_date": 0 },
"finalize": finalize
}
)
Chaque approche est susceptible de donner des résultats légèrement différents, mais c'est le point. Cela dépend de celui que vous souhaitez réellement utiliser.
Compte tenu de votre commentaire, vous pouvez soit "inspecter" la sortie de l'une ou l'autre déclaration et "remplir les lacunes" par programme pour ainsi dire. Je préfère généralement cette option, mais ce n'est pas mon programme et je ne sais pas quelle taille de série vous essayez de récupérer à partir de cette requête.
Côté serveur, vous pouvez patcher le "mapper" pour faire quelque chose comme ceci :
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
);
}