Using the mapReduce collection method with guidance from this answer you can get your desired results.
Here's a pymongo solution using the following options:
- map function - this does the initial mapping of the key, value pair to be emitted (the yearMonth and Amount).
- reduce function - didn't need any action for this case.
- out - specifies where to put the output - could be a collection or as in this case just processed inline.
- scope - specifies the rolling total field - just called total
- finalize - this does the actual totaling.
Here's the python(pymongo) code:
from pymongo import MongoClient
from bson.code import Code
client = MongoClient()
db = client.tst1
coll = db.mapr1
map1 = Code('''
function () {
emit(
this.yearMonth,
this.amount
);
}
''')
reduce1 = Code('''
function (key, values) {
return value;
}
''')
fin1 = Code('''
function(key, value) {
total += value;
return {amount: value, balance: total};
}
''')
result = coll.map_reduce(map1, reduce1, out={'inline': 1}, scope={'total': 0}, finalize=fin1)
for doc in result['results']:
print(f'The doc is {doc}')
Results:
The doc is {'_id': 201908.0, 'value': {'amount': 100.0, 'balance': 100.0}}
The doc is {'_id': 201909.0, 'value': {'amount': 100.0, 'balance': 200.0}}
The doc is {'_id': 201910.0, 'value': {'amount': 200.0, 'balance': 400.0}}
The doc is {'_id': 201911.0, 'value': {'amount': 100.0, 'balance': 500.0}}
The doc is {'_id': 201912.0, 'value': {'amount': 200.0, 'balance': 700.0}}
The doc is {'_id': 202001.0, 'value': {'amount': 300.0, 'balance': 1000.0}}
The doc is {'_id': 202002.0, 'value': {'amount': 200.0, 'balance': 1200.0}}
Documents in collection:
{'_id': ObjectId('5e89c410b187b1e1abb089af'),
'amount': 100,
'yearMonth': 201908}
{'_id': ObjectId('5e89c410b187b1e1abb089b0'),
'amount': 100,
'yearMonth': 201909}
{'_id': ObjectId('5e89c410b187b1e1abb089b1'),
'amount': 200,
'yearMonth': 201910}
{'_id': ObjectId('5e89c410b187b1e1abb089b2'),
'amount': 100,
'yearMonth': 201911}
{'_id': ObjectId('5e89c410b187b1e1abb089b3'),
'amount': 200,
'yearMonth': 201912}
{'_id': ObjectId('5e89c410b187b1e1abb089b4'),
'amount': 300,
'yearMonth': 202001}
{'_id': ObjectId('5e89c410b187b1e1abb089b5'),
'amount': 200,
'yearMonth': 202002}