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

3

6 Answers 6

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.

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

Comments

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.

2 Comments

+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).
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).
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];
      }
    }
  }
}

Comments

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

Comments

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
});

Comments

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/[email protected]"></script>

Disclaimer: I'm the author of object-scan

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.