Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

jQuery/JavaScript JSON object comparison

Is it possible to compare 2 sets of json objects for a difference? What I have is a script thats polling for JSON object via jquery $post(). What I want to do is take the object that was just polled and compare it to a stored one. Where if there is any changes from one to the other apply them to the stored object or replace it (either way) but from the UI perspective I am working with seamlessly apply the changes to what the JSON object is for by finding the differences between the 2. I want to do this because right now I have it so the UI is completely reloading per poll regardless of change or not which basically looks like ** from a UX perspective.

I figure if I can find the differences if any between the 2 objects I would fire off a function that I would have edit the UI specific to the differences.

like image 457
chris Avatar asked Nov 13 '11 00:11

chris


1 Answers

What I want to do is take the object that was just polled and compare it to a stored one. Where if there is any changes from one to the other apply them to the stored object or replace it (either way)

If you would be happy with a really simple "Has it changed in any way? Yes/No" solution, where if it has changed you just replace the previous object with the new one (as per the part of your question that I quoted), then you could save the JSON response before you parse it, i.e., save it in the string format in which your web-server sends it. Then when the next response comes in compare the new string with the old string. If they are different (or if it is the first request) parse the JSON and process it for display as appropriate. Naturally this assumes that your server-side code is creating the JSON strings in a consistent format (and not, e.g., changing the order of the properties).

If we assume you've already got (parsed) objects, an isEqual(a,b) function really should cope with nested objects, properties that are arrays, etc. This can be done recursively, and simply return true or false, but a getDifferences(a,b) function is going to get confusing in how it reports the differences within nested objects. Consider this simple example:

old: {"mum" : "Maria", "dad" : "Pierre", "kids" : ["Joe", "Mike", "Louisa"] }
new: {"mum" : "Julie", "dad" : "Pierre", "kids" : ["Joe", "Mary"] }

Is the difference {"mum" : "Julie", "kids" : ["Mary"]}? The "mum" has changed, and the list of "kids" has changed, but has "Mike" changed to "Mary", or are both "Mike" and "Louisa" gone with "Mary" being new, or...? Maybe it should be "kids": ["Joe","Mary"] because that's the new value. How do you indicate the deletions? That's just the first example off the top of my head where I don't know how you would want to handle the differences. It could quickly get worse: what if the "kids" array contained objects instead of strings to represent a whole family tree? What if the new "mum" property was ["Maria", "Julie"] (to allow for step-parents and so forth)?

If for your particular data you know you've only got one-dimensional objects then you can do something simple like the following:

function getDifferences(oldObj, newObj) {
   var diff = {};

   for (var k in oldObj) {
      if (!(k in newObj))
         diff[k] = undefined;  // property gone so explicitly set it undefined
      else if (oldObj[k] !== newObj[k])
         diff[k] = newObj[k];  // property in both but has changed
   }

   for (k in newObj) {
      if (!(k in oldObj))
         diff[k] = newObj[k]; // property is new
   }

   return diff;
}

The simplest change to the above to allow for nested objects is to just assume that if a property is an object/array then you only care whether it is different in any way and not dig down to report exactly which "sub-properties" have changed. If so, simply take the above function and change:

else if (oldObj[k] !== newObj[k])

to

else if (!isEqual(oldObj[k],newObj[k]))

Where isEqual() is one of the many comparison functions floating around the web or on StackOverflow.

(Note: I haven't bothered with .hasOwnProperty() above because I assume that objects that were returned to an Ajax request as JSON will not be inheriting properties from a prototype chain. Similarly an isEqual() function for this purpose wouldn't need to worry about properties being functions, it only needs to worry about what is valid in a JSON string.)

like image 193
nnnnnn Avatar answered Sep 18 '22 03:09

nnnnnn