Om det bara handlar om att få saker inom 10 sekunders intervaller, kan du göra lite matte och köra detta genom aggregatet:
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 }
}}
])
Så det bryter ner saker och ting till intervallen 10 sekunder på en minut där de inträffar med lite mod 10 matematik.
Jag tycker att det är rimligt och skulle vara den snabbaste löparen eftersom den använder aggregat. Om du verkligen behöver din sekvens som visas vara en löpande 10 sekunder från en initialt matchad tid, då kan du göra processen med mapReduce:
Först en kartläggare:
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
);
}
Så detta kommer att avge datum inom ett intervall på 10 sekunder, med början på det första datumet och sedan öka intervallet varje gång något hittas utanför intervallet
Nu behöver du en reducering:
var reducer = function (key, values) {
return values.length;
};
Väldigt enkelt. Returnera bara längden på arrayen som skickats in.
Eftersom mapReduce fungerar som det gör, skickas inte allt som inte har mer än ett värde till reduceraren, så rensa upp detta med finalize:
var finalize = function (key, value) {
if ( typeof(value) == "object" ) {
value = 1;
}
return value;
};
Sedan är det bara att köra det för att få resultatet. Notera avsnittet "omfattning" som skickar en global variabel som ska användas i mapparen:
db.collection.mapReduce(
mapper,
reducer,
{
"out": { "inline": 1 },
"scope": { "last_date": 0 },
"finalize": finalize
}
)
Varje tillvägagångssätt kommer sannolikt att ge lite olika resultat, men det är poängen. Det beror på vilken du faktiskt vill använda.
Med tanke på din kommentar kan du antingen "inspektera" resultatet från endera påståendet och "fylla i luckorna" så att säga programmässigt. Jag föredrar i allmänhet det alternativet, men det är inte mitt program och jag vet inte hur stor serie du försöker hämta från den här frågan.
På serversidan kan du korrigera "mapper" för att göra något som detta:
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
);
}