27

Say I have the following 2 json objects:

JSON A:
{
"Field A":"1",
"Field B":"2",
"Field D":"Something",
"Field E":"6"
}

JSON B:
{
"Field A":"1",
"Field B":"2",
"Field C":"3",
"Field D":"Different"
}

Sample Function: function (jsonstringA, jsonstringB)

Example (If JSON A and JSON B used as parameters):

Returns a new JSON object containing:

{
"Field C":"3", // because function sees jsonstringB had no "Field C"
"Field D": "Different" // sees jsonstringB had a different value for "Field D"
}

Note that it is using jsonstringA as the base of the comparison, so the function returns only the fields missing and values of jsonStringB. That is why "Field E" and its value is not returned.

What is the best way if possible to come up with a function that returns a json object containing values that have changed?

WHAT I HAVE TRIED: I have tried doing a comparison by manually specifying the fields that I am trying to check for, but I would like to have something that requires me to not hardcode the "Fields" as it is very inefficient and everytime I add a new field to JSON B, I have to hardcode in the field I am looking for... that is why I am looking for something less of a pain.

2

5 Answers 5

25

It's not too hard to create a function like this. Just loop through each field in the second object, and if it's not present in the first or the value is different than the first, put that field in the return object.

var compareJSON = function(obj1, obj2) {
  var ret = {};
  for(var i in obj2) {
    if(!obj1.hasOwnProperty(i) || obj2[i] !== obj1[i]) {
      ret[i] = obj2[i];
    }
  }
  return ret;
};

You can see it in action on this demo page.

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

4 Comments

Ah, ignore my comment, i assumed he also wanted a diff for variable number of properties for objects a and b. But it seems both objects have the same number of properties.
The OP probably would want to recurse into object and array values.
@Phrogz I'm not sure, from his description and example it seems like a shallow comparison is sufficient.
It would be nice if it could recurse through array values as I am curious about that, but a shallow recurse is sufficient. Thanks, you have helped save me from my hardcoded mess at least up until I end up having to deal with arrays.
5

You can have a look at json diff wrapper here

It has also demo page.You can use this wrapper.

Comments

5

The function, just what i was after is also useful for non - JSON object comparison

http://jsfiddle.net/muJEu/11/

Also extended it for deep nested objects.

isEmpty 

can be done in many ways. see Is object empty?

var compareObj = function(obj1, obj2) { 
  var ret = {},rett; 
  for(var i in obj2) { 
      rett = {};  
      if (typeof obj2[i] === 'object'){
          rett = compareObj (obj1[i], obj2[i]) ;
          if (!isEmpty(rett) ){
           ret[i]= rett
          }              
       }else{
           if(!obj1 || !obj1.hasOwnProperty(i) || obj2[i] !== obj1[i]) { 
              ret[i] = obj2[i]; 
      } 
   }
  } 
  return ret; 
}; 

4 Comments

This fails if a value is an array, because typeof [] === 'object'
This doesn't perform as expected if a property exists in obj1 but not in obj2. eg: a={a:true} b={b:true}. compareObj(a,b) // returns {b:true}. you might expect {a:true,b:true}
Where is rett defined, or is it a global variable?
rett is defined in line 2. var ret= {}, rett;
2

In the Peter Olson answer, it will not check for array values, to overcome from that issue, I have modified the solution like this.

var compareJSON = function(obj1, obj2) { 
      var ret = {}; 
      for(var i in obj2) { 
        if(!obj1.hasOwnProperty(i) || obj2[i] !== obj1[i]) {
          if(!Array.isArray(obj2[i]) || !(JSON.stringify(obj2[i]) == JSON.stringify(obj1[i]))){
          ret[i] = obj2[i];
          }
        } 
      } 
      return ret; 
    }; 

Comments

0

Affiliation: I am the author of this lib.

How about this: https://eggachecat.github.io/jycm-json-diff-viewer/ ? Not only it can detect by default but also you can set operators to do more customized diff.

enter image description here

Step by step:

  1. install deps
yarn add jycm
  1. use the lib
const {
    YouchamaJsonDiffer,
    ListItemFieldMatchOperator,
    make_ignore_order_func
} = require('jycm');

const left = {
  "Field A": "1",
  "Field B": "2",
  "Field D": "Something",
  "Field E": "6"
};

const right = {
  "Field A": "1",
  "Field B": "2",
  "Field C": "3",
  "Field D": "Different"
};

const ycm = new YouchamaJsonDiffer(left, right, {
  "operators": [
  
  ],
  "ignore_orders": [
  ]
});

const diffResult = ycm.get_diff(true);


const diffStat = {};

diffResult["value_changes"].forEach((record) => {
  diffStat[record.left_path] = "Different";
});

diffResult["dict:add"].forEach((record) => {
  diffStat[record.right_path] = record.right;
});

console.log(diffStat)

You can get

{
  "dict:add": [
    {
      "left": "__NON_EXIST__",
      "right": "3",
      "left_path": "",
      "right_path": "Field C"
    }
  ],
  "dict:remove": [
    {
      "left": "6",
      "right": "__NON_EXIST__",
      "left_path": "Field E",
      "right_path": ""
    }
  ],
  "value_changes": [
    {
      "left": "Something",
      "right": "Different",
      "left_path": "Field D",
      "right_path": "Field D",
      "old": "Something",
      "new": "Different"
    }
  ]
}
  1. make use of the result

it seems thank you only care about the dict:add and value_changes events:

const diffStat = {};

diffResult["value_changes"].forEach((record) => {
  diffStat[record.left_path] = "Different";
});

diffResult["dict:add"].forEach((record) => {
  diffStat[record.right_path] = record.right;
});

console.log(diffStat)

Or here's a codesniffet:

const {
  YouchamaJsonDiffer,
  ListItemFieldMatchOperator,
  make_ignore_order_func,
} = jycm;

const left = {
  "Field A": "1",
  "Field B": "2",
  "Field D": "Something",
  "Field E": "6"
};

const right = {
  "Field A": "1",
  "Field B": "2",
  "Field C": "3",
  "Field D": "Different"
};

const ycm = new YouchamaJsonDiffer(left, right, {
  "operators": [
  
  ],
  "ignore_orders": [
  ]
});

const diffResult = ycm.get_diff(true);


const diffStat = {};

diffResult["value_changes"].forEach((record) => {
  diffStat[record.left_path] = "Different";
});

diffResult["dict:add"].forEach((record) => {
  diffStat[record.right_path] = record.right;
});

console.log(diffStat)
<script src="https://unpkg.com/[email protected]/dist/index.js"></script>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.