1

I have a JSON file with nested objects, and I want to update specific values inside it using Python. The structure can vary, but it usually looks something like this:

{
  "user": {
    "name": "Jefferson",
    "details": {
      "age": 25,
      "city": "Guatemala"
    }
  },
  "active": true
}

I want to change the "city" value to "Antigua" and save the updated JSON back to the same file.

I tried this code:

import json

with open('data.json', 'r') as f:
    data = json.load(f)

data['user']['details']['city'] = 'Antigua'

with open('data.json', 'w') as f:
    json.dump(data, f, indent=4)

It works, but I’d like to know if there’s a more dynamic way to update values when I don’t know exactly how deep the key is nested (for example, when "city" could appear in multiple places).

What’s the best way in Python to search for a key in a nested JSON and update its value dynamically?

1
  • A similar question: How to update values in a nested dictionary? Although this answers builds a new dict, rather than updating an existing dict inplace. But it can easily be modified to modify the nested structure in place. Commented Nov 3 at 12:28

1 Answer 1

3

This is not just a question about JSON files, but rather one with Python dictionaries as a whole.

The main problem is that, no, there is no builtin way to do that. Python cannot unfortunately even tell if there is a key within a recursive dictionary inherently,, let alone change or modify it without specific instructions. You'd have to do a recursive search through the dict to solve the problem, which leads to problems with duplication and unlimited recursion.

If you know the general structure of the dictionary, like {"user": {"name": ..., "details": {}}}, then you can just do pretty much what you just did. Otherwise, you'd need a recursive search like I mentioned earlier:

def change_nested_dict_value(obj, key, value):
    if not isinstance(obj, dict):
        ## obj is not a nested dict
        return obj
    if key in obj:
        ## Key found!
        obj[key] = value
    for target_key, target_value in obj.items():
        obj[target_key] = change_nested_dict_value(target_value, key, value)
    return obj


obj = { "user": { "name": "Jefferson", "details": { "age": 25, "city": "Guatemala" } }, "active": True }
print(obj)
## Output: {'user': {'name': 'Jefferson', 'details': {'age': 25, 'city': 'Guatemala'}}, 'active': True}

obj = change_nested_dict_value(obj, "city", "Antigua")
print(obj)
## Output: {'user': {'name': 'Jefferson', 'details': {'age': 25, 'city': 'Antigua'}}, 'active': True}

(I didn't include the JSON loading in that to make things clearer, but you can add it in later)

That approach does have a problem though, that being it will change every occurrence of the key. You could theoretically make it so that it only changes the value once or something, but once you're getting into that territory, it might just be better to reformat your JSON file or only target specific parts of it (ie. only do one user at a time).

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.