Using update_one to update nested dictionary in pymongo (python mongoDB)

Viewed 2136

Suppose I have this function:

def insert_data(self, data, id):
    self.snapshots.update_one({'snapshot_id': id},
                              {'$set': {'topic': data}}, upsert=True) 

data is always a dictionary with a single entry (one key-value pair). each time this function is called, 'data' holds a different key. I want each call to add that key-value pair under 'topic'.

Let's say data is {1:2} at the first call and {3:4} at the second. I want to have {'topic': {1:2, 3:4}} after the two calls. How do I achieve that? The function above overwrites the data dictionary, so only the last one remains (at this case I end up with {'topic': {3:4}}).

It must not be that complicated but I was unable to get it to work properly.

1 Answers

As of mongodb version 4.2, you can use the Updates with Aggregation Pipeline new feature to get your desired results.

Just putting the brackets [] around the updates allows mongo to use aggregation and actually update the document.

Try something like this:

print(f'Document before update')
pprint.pprint(coll.find_one())


def insert_data(data, id):
    for key, value in data.items():
        coll.update_one({'snapshot_id': id}, 
                        [{'$set': {'topic': {str(key): value}}}])


data_dict = {1: 6, 3: 8, 5: 6}

for k, v in data_dict.items():
    insert_data({k: v}, 'Demo1')

    print(f'\nDocument after update')
    pprint.pprint(coll.find_one())

Results:

Document before update
{'_id': ObjectId('5e799063caf64cd83bfda524'), 'snapshot_id': 'Demo1'}

Document after update
{'_id': ObjectId('5e799063caf64cd83bfda524'),
 'snapshot_id': 'Demo1',
 'topic': {'1': 6}}

Document after update
{'_id': ObjectId('5e799063caf64cd83bfda524'),
 'snapshot_id': 'Demo1',
 'topic': {'1': 6, '3': 8}}

Document after update
{'_id': ObjectId('5e799063caf64cd83bfda524'),
 'snapshot_id': 'Demo1',
 'topic': {'1': 6, '3': 8, '5': 6}}
Related