Languages
[Edit]
EN

JavaScript - how to write own compare jsons function?

5 points
Created by:
AnnLen
9120

In this article, we're going to have a look at how to write own function to compare JSONs. Approach used in this article encloses each entity with object that keeps previous and current values with types and kind of change.

Example result:

{
    "name": "propertyName",
    "status": "changed",
    "oldType": "simple",
    "newType": "simple",
    "oldValue": "Some old value",
    "newValue": "Some new value"
}

Where:

  • status can be one of: unchanged, updated, created or deleted,
  • old and new type: array, object, simple or null,
  • old and new value: simple type object, array with enclosed entities that describe nested objects or null.

Note: read this article to see json difference visualization.

Run below example to see details. 

1. Custom diff method example

This section presents simple logic that returns object with difference information.

// ONLINE-RUNNER:browser;

function getType(object) {
  return Object.prototype.toString.call(object);
}

function getDescription(type) {
  if (type == '[object Array]') {
    return 'array';
  }
  if (type == '[object Object]') {
    return 'object';
  }
  return 'simple';
}

function createOldItem(name, status, type, value) {
  return {
    name: name || null,
    status: status,
    oldType: getDescription(type),
    newType: null,
    oldValue: value,
    newValue: null,
  };
}

function createNewItem(name, status, type, value) {
  return {
    name: name || null,
    status: status,
    oldType: null,
    newType: getDescription(type),
    oldValue: null,
    newValue: value,
  };
}

var createDeletedItem = function(key, type, value) {
  return createOldItem(key, 'deleted', type, value);
};

var createCreatedItem = function(key, type, value) {
  return createNewItem(key, 'created', type, value);
};

function coverContent(entity, createItem) {
  var items = [ ];

  for (const key in entity) {
    if (entity.hasOwnProperty(key)) {
      items.push(coverEntity(key, entity[key], createItem));
    }
  }

  return items;
}

function coverEntity(name, entity, createItem) {
  var type = getType(entity);

  if (type === '[object Array]' || type === '[object Object]') {
    var content = coverContent(entity, createItem);

    return createItem(name, type, content);
  } else {
    return createItem(name, type, entity);
  }
}

function compareContent(a, b) {
  var items = [ ];

  for (const key in a) {
    if (a.hasOwnProperty(key)) {
      if (b.hasOwnProperty(key)) {
        items.push(compareEntries(a[key], b[key], key));
      } else {
        items.push(coverEntity(key, a[key], createDeletedItem));
      }
    }
  }

  for (const key in b) {
    if (b.hasOwnProperty(key)) {
      if(a.hasOwnProperty(key)){
        continue;
      }

      items.push(coverEntity(key, b[key], createCreatedItem));
    }
  }

  return items;
}

function compareEntries(a, b, name) {
  var oldType = getType(a);
  var newType = getType(b);

  if (a === b) {
    return createOldItem(name, 'unchanged', oldType, a);
  }

  if (oldType == newType) {
    // both have array or object type:
    if (oldType === '[object Array]' || oldType === '[object Object]') {
      var oldValue = compareContent(a, b);

      return createOldItem(name, 'unchanged', oldType, oldValue);
    }
    // both have simple type: boolean, number, string, etc.:
    var description = getDescription(oldType);

    return {
      name: name || null,
      status: 'updated',
      oldType: description,
      newType: description,
      oldValue: a,
      newValue: b,
    };
  } else {
    // both have different types:
    var oldDescription = getDescription(oldType);
    var newDescription = getDescription(newType);

    return {
      name: name || null,
      status: 'updated',
      oldType: oldDescription,
      newType: newDescription,
      oldValue: (oldDescription == 'simple' ? a : coverContent(a, createDeletedItem)),
      newValue: (newDescription == 'simple' ? b : coverContent(b, createCreatedItem)),
    };
  }
}

function compareJsons(a, b) {
  var aEntity = JSON.parse(a);
  var bEntity = JSON.parse(b);

  return compareEntries(aEntity, bEntity);
}

// Usage example:

var json1 = '{"name":"John","items":[1,2,"3",{"name":"Item","z":[4]},5]}';
var json2 = '{"name":"John","items":["1",2,3,{"name":"Item 2","x":3}]}';

var difference = compareJsons(json1, json2);

console.log(JSON.stringify(difference));

Formatted result:

{
   "name": null,
   "status": "unchanged",
   "oldType": "object",
   "newType": null,
   "oldValue": [
      {
         "name": "name",
         "status": "unchanged",
         "oldType": "simple",
         "newType": null,
         "oldValue": "John",
         "newValue": null
      },
      {
         "name": "items",
         "status": "unchanged",
         "oldType": "array",
         "newType": null,
         "oldValue": [
            {
               "name": "0",
               "status": "updated",
               "oldType": "simple",
               "newType": "simple",
               "oldValue": 1,
               "newValue": "1"
            },
            {
               "name": "1",
               "status": "unchanged",
               "oldType": "simple",
               "newType": null,
               "oldValue": 2,
               "newValue": null
            },
            {
               "name": "2",
               "status": "updated",
               "oldType": "simple",
               "newType": "simple",
               "oldValue": "3",
               "newValue": 3
            },
            {
               "name": "3",
               "status": "unchanged",
               "oldType": "object",
               "newType": null,
               "oldValue": [
                  {
                     "name": "name",
                     "status": "updated",
                     "oldType": "simple",
                     "newType": "simple",
                     "oldValue": "Item",
                     "newValue": "Item 2"
                  },
                  {
                     "name": "z",
                     "status": "deleted",
                     "oldType": "array",
                     "newType": null,
                     "oldValue": [
                        {
                           "name": "0",
                           "status": "deleted",
                           "oldType": "simple",
                           "newType": null,
                           "oldValue": 4,
                           "newValue": null
                        }
                     ],
                     "newValue": null
                  },
                  {
                     "name": "x",
                     "status": "created",
                     "oldType": null,
                     "newType": "simple",
                     "oldValue": null,
                     "newValue": 3
                  }
               ],
               "newValue": null
            },
            {
               "name": "4",
               "status": "deleted",
               "oldType": "simple",
               "newType": null,
               "oldValue": 5,
               "newValue": null
            }
         ],
         "newValue": null
      }
   ],
   "newValue": null
}

 

Native Advertising
50 000 ad impressions - 449$
🚀
Get your tech brand or product in front of software developers.
For more information contact us:
Red dot
Dirask - friendly IT community for everyone.

❤️💻 🙂

Join