1

I have multiple json files containing relational data which I need to merge , each of the file has a record with commonkey which is common key in all files, in the example below a0 ,a1 are common keys.The value is a nested dictionary of multiple keys like Key1, key2 etc as shown below, I need to merge the multiple json files and get the output as shown in the dboutput.json, with the file name acting as the index in the merging operation. Such question is a related question which merges loosing information, but in my case I dont want any updation which replaces the existing keys or skips updations, in case of hitting an existing key another nested dictionary indexed by the filename is created as shown below:

Example:

File db1.json:


"a0": {
        "commonkey": [
            "a1", 
            "parentkeyvalue1"
        ], 
        "key1": "kvalue1", 
        "key2": "kvalue2"
        "keyp": "kvalue2abc"

    }, 
"a1": { 
...
}

File db2.json:


"a0": {
        "commonkey": [
            "a1", 
            "parentkeyvalue1"
        ], 
        "key1": "kvalue1xyz", 
        "key2": "kvalue2",
        "key3": "kvalue2"



    }, 

"a1": { 
...
}

Desired Output

File dboutput.json

"a0": {
        "commonkey": [
            "a1", 
            "parentkeyvalue1"
        ], 
        "key1": {"db1":"kvalue1","db2":"kvalue1xyz"} ,
        "key2": {"db1":"kvalue2","db2":"kvalue2"} ,
        "key3": {"db2":"kvalue2"}
        "keyp": {"db1":"kvalue2abc"}



    }, 
"a1": { 
...
}

So how to do such lossless merges? Note "key2": {"db1":"kvalue2","db2":"kvalue2"} even if the key\value pairs are same they need to be stored separately. In effect the output is a union of all input files and has all entries from all other files.

Also

"commonkey": [
            "a1", 
            "parentkeyvalue1"
        ],

will be same for all files and hence need not be repeated

Community
  • 1
  • 1
stackit
  • 3,036
  • 9
  • 34
  • 62

2 Answers2

2

I finally managed to get it:

class NestedDict(collections.OrderedDict):
    """Implementation of perl's autovivification feature."""
    def __getitem__(self, item):
        try:
            return dict.__getitem__(self, item)
        except KeyError:
            value = self[item] = type(self)()
            return value

def mergejsons(jsns):
 ##use auto vification Nested Dict
    op=nesteddict.NestedDict()
    for j in jsns:
        jdata=json.load(open(j))
        jname=j.split('.')[0][-2:]
        for commnkey,val in jdata.items():
            for k,v in val.items():
                if k!='commonkey':
                    op[commnkey][k][jname]=v
                if  op[commnkey].has_key('commonkey'):
                    continue
                else:
                    op[commnkey][k][jname]=v
stackit
  • 3,036
  • 9
  • 34
  • 62
1

A simple solution is to iterate through each JSON object, and add dictionary pairs in each "commonkey" as you see them. Here's an example where you load each JSON file in a list, and then iteratively merge them.

#!/usr/bin/python
import json

# Hardcoded list of JSON files
dbs = [ "db1.json", "db2.json" ]
output = dict() # stores all the merged output

for db in dbs:
    # Name the JSON obj and load it 
    db_name = db.split(".json")[0]
    obj = json.load(open(db))

    # Iterate through the common keys, adding them only if they're new
    for common_key, data in obj.items():
        if common_key not in output:
            output[common_key] = dict(commonkey=data["commonkey"])

        # Within each common key, add key, val pairs 
        # subindexed by the database name
        for key, val in data.items():
            if key != "commonkey":
                if key in output[common_key]:
                    output[common_key][key][db_name] = val
                else:
                    output[common_key][key] = {db_name: val}


# Output resulting json to file
open("dboutput.json", "w").write( 
    json.dumps( output, sort_keys=True, indent=4, separators=(',', ': ') )
)
mdml
  • 22,442
  • 8
  • 58
  • 66