Home > Back-end >  How to update only a part of a json which is stored in a database with a "json path" list?
How to update only a part of a json which is stored in a database with a "json path" list?

Time:12-14

Let´s say we have a database and there is a json stored as a string which contains configurations. In the application we want to update only a specific value and write then back the json as a string to the database.

The HTTP request provides a "jsonPath" which reflects a path in the json file to navigate to the object we want to update. This parameter is supplied as a list.

An example for the path could be something like ['input', 'keyboard', 'language'] and the value we want to set is 'en'

Here we load the configuration from the database which works so far:

if request.data['jsonPath']: 
    config =  json.loads(models.Config.objects.get(name__startswith='general').value

Then config is just a normal object now, which I can access with the dot notation like config.input.keyboard.language and it contains then the according part in json syntax.

I am able to read out the value of the field with the following syntax:

config[request.data['jsonPath'][0]][request.data['jsonPath'][1]][request.data['jsonPath'[3]]

But the number of parameters can vary and I want also to write it back into the config object, convert it back to a string and write it into the database.

I know it is not a nice thing but I would be interessted how it can be done like this

CodePudding user response:

Assuming you have a nested json object like this:

mydict = {
    'key1': {
        'key2': {
            'key3': {
                'foo': 'bar'
            },
        },
    },
}

And you have a "path" list like this:

path = ['key1', 'key2', 'key3']

You can traverse the path like this:

data = mydict
for key in path:
    data = data[key]

data will end up as the value of the last item in path, in this case the subdict {'foo': 'bar'}

CodePudding user response:

You can use functools.reduce for this:

functools.reduce(dict.get, path, data)

from functools import reduce

data = {'key1': {'key2': {'key3': {'foo': 'bar'}}}}
path = ['key1', 'key2', 'key3']

reduce(dict.get, path, data)["foo"] = baz

Result:

{'key1': {'key2': {'key3': {'foo': 'baz'}}}}

P.S

If the data type of data is something else you could possibly use operator.itemgetter

  • Related