Unordered JSON compare for differences using javascript

Sometimes we need to programmatically compare JSON from two or more sources and determine what's the difference between them.

The program below can do deep compare JSON even if they are not in the same order or conatins substructures and arrays. It provides the detailed list of mismatches and misses in both JSON's by calling out attributes with the same keys and different values or missing keys.

 const obj1={  
   "k1":"aq",  
   "k2":"b",  
   "k3":"c",  
   "k4":{  
    "kk1":"aq",  
    "kk2":"b",  
    "kk3":"c",  
    "kk4":{  
     "kkk1":""  
    },  
    "kk5":"abc"  
   },  
   "k5":[{"kk5":"abc","kk6":"53"},{"kk5":"abc","kk6":"54"}]  
   }  
 const obj2={  
   "k1":"a",  
   "k2":"b",  
   "k4":{  
    "kk1":"agq",  
    "kk3":"c",  
    "kk4":{  
     "kkk1":"x"  
    },  
    "kk5":{  
     "kkk1":"b"  
    }  
   },  
   "k5":[{"kk5":"abc"},{"kk5":"abc","kk6":"53"}]  
 }  
 function isObject(obj){  
  return obj !== undefined && obj !== null && obj.constructor === Object;  
 }  
 function getObjectDiff(obj1, obj2, parent){  
  let result = [];  
  Object.keys(obj1).forEach(k =>{  
   let prefix = parent ? parent + "." + k : k;  
   if(!obj2.hasOwnProperty(k)){  
    result.push(prefix);  
   }else if(Array.isArray(obj1[k]) && Array.isArray(obj2[k])){  
    let mismatches = [];  
     index=0;  
     for(let item of obj1[k]){  
      let misses = getObjectMissInArray(item,obj2[k],prefix,index)  
      if(misses !== null){  
       mismatches = mismatches.concat(misses);  
      }  
      index++;  
     }  
     result = result.concat(mismatches);  
   }else if(Array.isArray(obj1[k]) || Array.isArray(obj2[k])){  
    result.push(prefix);  
   }else if(isObject(obj1[k]) && isObject(obj2[k])){  
    result = result.concat(getObjectDiff(obj1[k],obj2[k],prefix));  
   }else if(isObject(obj1[k]) || isObject(obj2[k])){  
    result.push(prefix);  
   } else if(obj1[k] !== obj2[k]){  
    result.push(prefix);  
   }  
 })  
 return result  
 }  
 function getObjectMissInArray(obj, array,parent,index){  
  let result = []  
  for(let item of array){  
   let diff1 = getObjectDiff(obj,item,parent+"["+index+"]");  
   let diff2 = getObjectDiff(item,obj,parent+"["+index+"]");  
   let diff = diff1.concat(diff2);  
   if(diff.length !== 0){  
    result = result.concat(diff)  
   }else{  
    result =[]  
   }  
  }  
  return result.length > 0 ? result : null;  
 }  
 function objectDiff(obj1,obj2){  
  let diff1 = getObjectDiff(obj1,obj2,"");  
  let diff2 = getObjectDiff(obj2,obj1,"");  
  let results=[];  
  for(let item of diff1){  
   if(diff2.includes(item) && !results.includes(item)){  
    results.push(item);  
   }else{  
    if(!results.includes(item)){  
     results.push("obj1."+item);  
    }  
   }  
  }  
  for(let item of diff2){  
   if(!results.includes(item) && !results.includes("obj2."+item)){  
    results.push("obj2."+item);  
   }  
  }  
  return results;  
 }  
 console.log(objectDiff(obj1,obj2,""))  

"Obj1" and "Obj2" are sample objects and the output of above program is 

 [  
  'k1',  
  'obj1.k3',  
  'k4.kk1',  
  'obj1.k4.kk2',  
  'k4.kk4.kkk1',  
  'k4.kk5',  
  'k5[1].kk6',  
  'obj2.k5[0].kk6'  
 ]  

The keys prefixed with "obj" show the item belonging to what object, it means it's not present in other object. 

Comments

Popular posts from this blog

Caused by: java.sql.SQLTimeoutException: ORA-01013: user requested cancel of current operation

HashiCorp Vault Integration with Ansible Etower using approle

utility to extract date from text with java