Stryker Stryker - 4 months ago 7
JSON Question

Update a dictionary value using python

I have a json file, which when loaded in python using

json.loads()
becomes a
dictionary
. The json data is a
nested dictionary
which can contain a
'groups'
key inside another
'groups'
key. The values inside the
'groups'
key are a
'name'
key and a
'properties'
key.

Each
'properties'
key has a unique
'name'
and a
'value'
key.

My objective is to search for a
'groups'
key having its
'name'
key value as
"SportCar"
, which has a
properties
key having a
name
key value as
"BMW"
, and only when these conditions are satisfied, update the
'data'
key from
'data':value1
to
'data':value2
.

An example of the json is as follows

{
"groups": [
{
"name": "SportCar",
"properties": [
{
"name": "BMW",
"value": {
"type": "String",
"encoding": "utf-8",
"data": "value1"
}
},
{
"name": "Audi",
"value": {
"type": "Boolean",
"data": true
}
}
],
"groups": [
{
"name": "Trucks",
"properties": [
{
"name": "Volvo",
"value": {
"type": "String",
"encoding": "utf-8",
"data": "value1"
}
}
]
}
]
},
{
"name": "MotorCycle",
"properties": [
{
"name": "Yamaha",
"value": {
"type": "String",
"encoding": "utf-8",
"data": "value1"
}
}
],
"groups": [
{
"name": "Speeders",
"properties": [
{
"name": "prop2",
"value": {
"type": "String",
"encoding": "utf-8",
"data": "value1"
}
}
]
}
]
}
]
}


The above json is contained in myjson22.json. Here is what I have tried so far:

import json
from pprint import pprint

json_data=open('myjson22.json', 'r')
data = json.load(json_data)
#print(data)

def get_recursively(search_dict, field):
"""
To read the json data as type dict and search all 'groups' keys for the 'name' key value value provided.
"""
fields_found = []

for key, value in search_dict.items():

if key == field:
fields_found.append(value)

elif isinstance(value, dict):
results = get_recursively(value, field)
for result in results:
fields_found.append(result)

elif isinstance(value, list):
for item in value:
if isinstance(item, dict):
more_results = get_recursively(item, field)
for another_result in more_results:
fields_found.append(another_result)

return fields_found
get_recursively(data, ["properties"][0])


and the output was:

[[{'name': 'BMW',
'value': {'data': 'value1', 'encoding': 'utf-8', 'type': 'String'}},
{'name': 'Audi', 'value': {'data': True, 'type': 'Boolean'}}],
[{'name': 'Volvo',
'value': {'data': 'value1', 'encoding': 'utf-8', 'type': 'String'}}],
[{'name': 'Yamaha',
'value': {'data': 'value1', 'encoding': 'utf-8', 'type': 'String'}}],
[{'name': 'prop2',
'value': {'data': 'value1', 'encoding': 'utf-8', 'type': 'String'}}]]

Answer

A way to implement this recursive solution is with backtracking. When no more 'groups' keys are are found nested inside the root key, the 'name' key value is matched with groups_name parameter, which is 'SportCar' in our case. If this condition is satisfied check for the values inside same 'groups' key's (i.e. 'SportCar' key's) 'properties' key and match its 'name' key value with the properties_name parameter (which is 'BMW' in our case). If this second condition is also true, then update the 'data' key value inside the same 'properties' key, as per requirements, or else return (for backtracking).

import json

json_data = open('myjson22.json', 'r')

data = json.load(json_data)

def get_recursively( myJson, groups_name, properties_name, value2):

    if 'groups' in myJson.keys():
        # As there are multiple values inside 'groups' key
        for jsonInsideGroupsKey in myJson['groups']:  
            get_recursively( jsonInsideGroupsKey, groups_name, properties_name, value2)

    if 'name' in myJson.keys():
        # check for groups name
        if myJson['name'] == groups_name:
            # check for properties name
            if myJson['properties'][0]['name'] == properties_name:
                # Update value. The changes will persist as we backtrack because
                # we are making the update at the original memory location
                # and not on a copy. For more info see deep and shallow copy.
                myJson['properties'][0]['value']['data'] = value2
    return

get_recursively(data,'SportCar','BMW','changedValue1')
get_recursively(data,'Speeders','prop2','changedValue2')
print data

my output:

{u'groups': [{u'name': u'SportCar', u'groups': [{u'name': u'Trucks', u'properties': [{u'name': u'Volvo', u'value': {u'data': u'value1', u'type': u'String', u'encoding': u'utf-8'}}]}], u'properties': [{u'name': u'BMW', u'value': {u'data': 'changedValue1', u'type': u'String', u'encoding': u'utf-8'}}, {u'name': u'Audi', u'value': {u'data': True, u'type': u'Boolean'}}]}, {u'name': u'MotorCycle', u'groups': [{u'name': u'Speeders', u'properties': [{u'name': u'prop2', u'value': {u'data': 'changedValue2', u'type': u'String', u'encoding': u'utf-8'}}]}], u'properties': [{u'name': u'Yamaha', u'value': {u'data': u'value1', u'type': u'String', u'encoding': u'utf-8'}}]}]}

prettified it will look as:

{
  "groups": [
    {
      "name": "SportCar",
      "properties": [
    {
      "name": "BMW",
      "value": {
        "type": "String",
        "encoding": "utf-8",
        "data": "ChangedValue1"
      }
    },
    {
      "name": "Audi",
      "value": {
        "type": "Boolean",
        "data": true
      }
    }
      ],
      "groups": [
    {
      "name": "Trucks",
      "properties": [
        {
          "name": "Volvo",
          "value": {
            "type": "String",
            "encoding": "utf-8",
            "data": "value1"
          }
        }
      ]
    }
      ]
    },
    {
      "name": "MotorCycle",
      "properties": [
    {
      "name": "Yamaha",
      "value": {
        "type": "String",
        "encoding": "utf-8",
        "data": "value1"
      }
    }
      ],
      "groups": [
    {
      "name": "Speeders",
      "properties": [
        {
          "name": "prop2",
          "value": {
            "type": "String",
            "encoding": "utf-8",
            "data": "ChangedValue2"
          }
        }
      ]
    }
      ]
    }
  ]
}