Tu error es cómo estás calculando _id para $group operador, específicamente su second parte:
second: { $subtract: [
{ $second: "$time" },
{ $mod: [
{ $second: "$time" },
timeBlock / 1000
]}
]}
Entonces, en lugar de dividir todos sus datos en 10 timeBlock fragmentos de milisegundos de largo a partir de new Date(end - 10 * timeBlock) , lo estás dividiendo en 11 partes a partir del divisor más cercano de timeBlock .
Para solucionarlo, primero debe calcular delta = end - $time y luego utilícelo en lugar del original $time para construir su _id .
Aquí hay un ejemplo de lo que quiero decir:
Document.aggregate({
$match: {
time: {
$gte: new Date(end - 10 * timeBlock),
$lt: new Date(end)
}
}
}, {
$project: {
time: 1,
delta: { $subtract: [
new Date(end),
"$time"
]}
}
}, {
$project: {
time: 1,
delta: { $subtract: [
"$delta",
{ $mod: [
"$delta",
timeBlock
]}
]}
}
}, {
$group: {
_id: { $subtract: [
new Date(end),
"$delta"
]},
count: { $sum: 1 }
}
}, {
$project: {
time: "$_id",
count: 1,
_id: 0
}
}, {
$sort: {
time: 1
}
}, function(err, result) {
// ...
})
También te recomiendo que uses valores de tiempo sin procesar (en milisegundos), porque es mucho más fácil y evitará que cometas un error. Podrías lanzar time en timeParts después de $group usando $project operador.