Running Total of Elements in a Single Collection Over Time

Goal: Visualze the growth over time of a user base or any other element in a collection. A prerequisite is that every element has a date field - the date on which it was created.

Approach: We need to split our collection entries into series elements per day to then accumulate them together.

We can do this using the following query:
Note: Line 9 holds the date format configuration that could e.g. be changed to separate the dates by calender week, month, year or any other preferred date time

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
{
"collection": "users",
"aggregate": [
{
"$group": {
"_id": {
"time": {
"$dateToString": {
"format": "%Y-%m-%d",
"date": "$_created"
}
}
},
"value": {
"$sum": 1
}
}
},
{
"$addFields": {
"_id": "$_id.time"
}
},
{
"$sort": [
{
"name": "_id",
"direction": 1
}
]
},
{
"$group": {
"_id": null,
"data": {
"$push": "$$ROOT"
}
}
},
{
"$addFields": {
"data": {
"$reduce": {
"input": "$data",
"initialValue": {
"total": 0,
"d": []
},
"in": {
"total": {
"$sum": [
"$$this.value",
"$$value.total"
]
},
"d": {
"$concatArrays": [
"$$value.d",
[
{
"_id": "$$this._id",
"value": "$$this.value",
"runningTotal": {
"$sum": [
"$$value.total",
"$$this.value"
]
}
}
]
]
}
}
}
}
}
},
{
"$unwind": "$data.d"
},
{
"$replaceRoot": {
"newRoot": "$data.d"
}
}
]
}

Our output is a table that contains every ‘new’ element count per day, as well as the then accumulated total value

1
2
3
4
5
6
7
8
|     date | value  | runningTotal  |
|---------:|-------:|--------------:|
| 07/02/22 | 3 | 3 |
| 08/02/22 | 3 | 6 |
| 09/02/22 | 1 | 7 |
| 10/02/22 | 4 | 11 |
| 11/02/22 | 3 | 14 |
| 14/02/22 | 7 | 21 |
Share