18

I have two JSON objects in Javascript, identical except for the numerical values. It looks like this:

var data = {
  "eth0":{"Tx":"4136675","Rx":"13232319"},
  "eth1":{"Tx":"4","Rx":"0"},
  "lo":{"Tx":"471290","Rx":"471290"}
}

var old = {
  "eth0":{"Tx":"4136575","Rx":"13232219"},
  "eth1":{"Tx":"4","Rx":"0"},
  "lo":{"Tx":"471290","Rx":"471290"}
}

One object called "data" has the current values, another object called "old" has the same values from 1 second ago. I'd like to output a JSON object with only the change in values so I can calculate data throughput on the network interfaces.

var throughput = {
  "eth0":{"Tx":"100","Rx":"100"},
  "eth1":{"Tx":"0","Rx":"0"},
  "lo":{"Tx":"0","Rx":"0"}
}

I'm not sure how to go about traversing the JSON data - it could be for any number of interfaces.

Can anyone please lend me a hand? Thanks in advance

Al.
  • 2,872
  • 2
  • 22
  • 34
  • A good answer also found here: [How can you map the differences between JavaScript objects?](http://codereview.stackexchange.com/questions/11412/how-can-you-map-the-differences-between-javascript-objects/11580#11580) – laggingreflex Jun 23 '14 at 08:51
  • for client-side comparision, perhaps http://tlrobinson.net/projects/javascript-fun/jsondiff/ may be useful. – Veverke Oct 22 '14 at 15:00
  • Does this answer your question? [Generic deep diff between two objects](https://stackoverflow.com/questions/8572826/generic-deep-diff-between-two-objects) – Michael Freidgeim Apr 23 '20 at 19:40

6 Answers6

14

The basic premise for iterating over objects in JavaScript is like so

var whatever = {}; // object to iterate over
for ( var i in whatever )
{
  if ( whatever.hasOwnProperty( i ) )
  {
     // i is the property/key name
     // whatever[i] is the value at that property
  }
}

Fixing up a checker wouldn't be too hard. You'll need recursion. I'll leave that as an exercise for you or another SOer.

Peter Bailey
  • 105,256
  • 31
  • 182
  • 206
10

Maybe it's already answered enough, but let me add my shameless plug :) A JSON (actually any javascript object or array structure) diff & patch library I open sourced at github:

https://github.com/benjamine/jsondiffpatch

it generates diffs (also in JSON format, and with a small footprint), which you can use client (check the test page) & server side, and if present, it uses http://code.google.com/p/google-diff-match-patch/ for long strings automatically.

check the DEMO page to see how it works.

Benja
  • 4,099
  • 1
  • 30
  • 31
  • +1 A sophisticated json diff algorithm, e.g. with string attributes, the decision whether to use the complete *before* and *after* string or do a diff **inside** the string, depending on the length of the resulting diff (I assume). – Evgeniy Berezovsky Aug 06 '12 at 10:28
  • Yes, a text diff is done when 2 long (how long is configurable) strings are found (in order to reduce diff size, and also to allow fuzzy patching). – Benja Aug 06 '12 at 14:57
7

You can iterate through the parent and child object properties:

var diff = {};
for(var p in data){
  if (old.hasOwnProperty(p) && typeof(data[p]) == 'object'){
    diff[p] = {};
    for(var i in data[p]){
      if (old[p].hasOwnProperty(i)){
        diff[p][i] = data[p][i] - old[p][i];
      }
    }
  }
}
dev.e.loper
  • 35,446
  • 76
  • 161
  • 247
Christian C. Salvadó
  • 807,428
  • 183
  • 922
  • 838
5

This did the trick for me when dealing with a similar problem. It gets the differences in second compared to first.

var first  = originalObj;
var second = modifiedObj;
var diff   = {};

var differ = function(first, second, result) {
    var i = 0;
    for (i in first) {
        if (typeof first[i] == "object" && typeof second[i] == "object") {
            result[i] = differ(first[i], second[i], {});
            if (!result[i]) delete result[i];
        } else if (first[i] != second[i]) {
            result[i] = second[i];
        }
    }
    return isEmpty(result) ? undefined : result;
}

differ(old_conf, new_conf, diff);

Code is a bit of a special case, but you get the general idea :P

wjandrea
  • 28,235
  • 9
  • 60
  • 81
asbjornenge
  • 1,209
  • 13
  • 16
0

You can use an object traversal module like nervgh/object-traverse to do this.

var result = {}
Object.traverse(old, function(node, value, key, path) {
  var resultObject = result
  for(var n=0; n<path.length-1; n++) {
    resultObject = resultObject[path[n]]
  }
  resultObject[key] = value
});
B T
  • 57,525
  • 34
  • 189
  • 207
0

Here is a solution using object-scan. Haven't tested it, but this solution should be very fast as we keep track of the two references

// const objectScan = require('object-scan');

const data = { eth0: { Tx: '4136675', Rx: '13232319' }, eth1: { Tx: '4', Rx: '0' }, lo: { Tx: '471290', Rx: '471290' } };

const old = { eth0: { Tx: '4136575', Rx: '13232219' }, eth1: { Tx: '4', Rx: '0' }, lo: { Tx: '471290', Rx: '471290' } };

const computeThroughput = (dataOld, dataNew) => objectScan(['**'], {
  breakFn: ({ property, value, context: { stack, result } }) => {
    if (property === undefined) {
      return;
    }

    const stackRef = stack[stack.length - 1][property];
    stack.push(stackRef);

    const resultRefParent = result[result.length - 1];
    if (!(property in resultRefParent)) {
      if (typeof stackRef === 'string') {
        resultRefParent[property] = String(Number.parseFloat(stackRef) - Number.parseFloat(value));
      } else {
        resultRefParent[property] = {};
      }
    }
    const resultRef = resultRefParent[property];
    result.push(resultRef);
  },
  filterFn: ({ context: { stack, result } }) => {
    stack.pop();
    result.pop();
  }
})(dataOld, {
  stack: [dataNew],
  result: [{}]
}).result[0];

console.log(computeThroughput(old, data));
/* => {
  lo: { Rx: '0', Tx: '0' },
  eth1: { Rx: '0', Tx: '0' },
  eth0: { Rx: '100', Tx: '100' }
} */
.as-console-wrapper {max-height: 100% !important; top: 0}
<script src="https://bundle.run/object-scan@13.8.0"></script>

Disclaimer: I'm the author of object-scan

vincent
  • 1,953
  • 3
  • 18
  • 24