Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to get only the "changed" values from two JSON objects

This is a question that involves a more complicated way of comparison, Thus it's not a duplicate

I've created a JqTree, that when the user changes its tree structure, both "old" JSON and "new" JSON structures should be compared, and it should be shown only the values of the JSON that has been changed.

For example:

[{"name":"node1","id":1,"is_open":true,"children":
    [
      {"name":"child1","id":2},
      {"name":"child2","id":3}
    ]
}]

Example

After the client has placed child1 under child2

[{"name":"node1","id":1,"is_open":true,"children":
  [
    {"name":"child2","id":3},
    {"name":"child1","id":2}
  ]
}]

example

I just would like to compare them and check which values were changed and show them with an alert, which, in this case, would be:

{"name":"child2","id":3},
{"name":"child1","id":2}

So far I have this tiny code that compares them:

JSON.stringify(object1) === JSON.stringify(object2); //I know it's not too reliable.

But I'm looking for something that checks the "difference" and extracts it from the JSON.

Thanks in advance.

like image 443
Kyle Avatar asked Sep 20 '25 09:09

Kyle


1 Answers

Here you go: http://jsfiddle.net/musicin3d/cf5ddod1/3/

Edited down version for your no-clicking pleasure:

// Call this function.
// The others are helpers for this one.
function getDiff(a, b){
    var diff = (isArray(a) ? [] : {});
    recursiveDiff(a, b, diff);
    return diff;
}

function recursiveDiff(a, b, node){
    var checked = [];

    for(var prop in a){
        if(typeof b[prop] == 'undefined'){
            addNode(prop, '[[removed]]', node);
        }
        else if(JSON.stringify(a[prop]) != JSON.stringify(b[prop])){
            // if value
            if(typeof b[prop] != 'object' || b[prop] == null){
                addNode(prop, b[prop], node);
            }
            else {
                // if array
                if(isArray(b[prop])){
                   addNode(prop, [], node);
                   recursiveDiff(a[prop], b[prop], node[prop]);
                }
                // if object
                else {
                    addNode(prop, {}, node);
                    recursiveDiff(a[prop], b[prop], node[prop]);
                }
            }
        }
    }
}

function addNode(prop, value, parent){
        parent[prop] = value;
}

function isArray(obj){
    return (Object.prototype.toString.call(obj) === '[object Array]');
}

See the link above for more details. There is a comment that explains some of my assumptions.

This is an example of how to use recursion to solve your problem. If you're not familiar with recursion, I suggest you do some reading. Here's a SO article about it: What is recursion and when should I use it?

Of note:
Using JSON.stringify like I did is not a good idea. It's convenient for me as the programmer because my program can "look ahead" to see if there's a change down each path, but that comes at a cost. I'm already traversing the tree structure to do my work, and JSON.stringify also traverses the tree structure of every object I send every time I call it. In computer science we call this a worst case scenario of O(n!), less formally referred to as "very slow." A better design would just traverse the entire tree and keep track of how it got to where it was. When it came to a dead end (called a "leaf" node"), it would use this knowledge to add the necessary data structure to the diff variable all at once. This would mean our program would have to traverse the entire data structure, but our code would be the only thing doing it. So each node would be processed only once.

Still, this should give you an idea of what others were suggesting.

like image 56
musicin3d Avatar answered Sep 22 '25 03:09

musicin3d