Detta gör vad du behöver. Jag har normaliserat tiderna i datan så att de grupperar sig (du kan göra något sånt här). Tanken är att $group
och tryck på time
s och total
är i separata arrayer. Sedan $unwind
time
array, och du har gjort en kopia av totals
array för varje time
dokumentera. Du kan sedan beräkna runningTotal
(eller något som det rullande medelvärdet) från arrayen som innehåller all data för olika tidpunkter. "Index" som genereras av $unwind
är arrayindex för total
som motsvarar den time
. Det är viktigt att $sort
före $unwind
eftersom detta säkerställer att arrayerna är i rätt ordning.
db.temp.aggregate(
[
{
'$group': {
'_id': '$time',
'total': { '$sum': '$value' }
}
},
{
'$sort': {
'_id': 1
}
},
{
'$group': {
'_id': 0,
'time': { '$push': '$_id' },
'totals': { '$push': '$total' }
}
},
{
'$unwind': {
'path' : '$time',
'includeArrayIndex' : 'index'
}
},
{
'$project': {
'_id': 0,
'time': { '$dateToString': { 'format': '%Y-%m-%d', 'date': '$time' } },
'total': { '$arrayElemAt': [ '$totals', '$index' ] },
'runningTotal': { '$sum': { '$slice': [ '$totals', { '$add': [ '$index', 1 ] } ] } },
}
},
]
);
Jag har använt något liknande på en samling med ~80 000 dokument, sammanlagt till 63 resultat. Jag är inte säker på hur bra det kommer att fungera på större samlingar, men jag har funnit att att utföra transformationer (projektioner, arraymanipulationer) på aggregerad data inte verkar ha en stor prestandakostnad när data har reducerats till en hanterbar storlek.