0

I have 2 deep nested object of objects. One is a "base" object and the other is a modified one.

I essentially want to "delete" the base object from the modified object and return an object that only contains different data. Here is an example:

Base object:

baseObj : {
    image: {
        width: '100%',
        paddingTop: '0px',
        paddingRight: '0px',
        paddingBottom: '0px',
        paddingLeft: '0px'
    },
    wrap: {
        marginTop: '0px',
        marginRight: '0px',
        marginBottom: '0px',
        marginLeft: '0px'
    }
}

Object with modified data

mergedObject : {
    image: {
        width: '100%',  
        paddingTop: '0px',
        paddingRight: '24px', // modified value
        paddingBottom: '24px', // modified value
        paddingLeft: '0px'
    },
    wrap: {
        height: '100px', // new value
        marginTop: '24px', // modified value
        marginRight: '0px',
        marginBottom: '0px',
        marginLeft: '24px' // modified value
    }
}

I would like an object that is returned like this:

diffObject : {
    image: {
        paddingRight: '24px',
        paddingBottom: '24px',
    },
    wrap: {
        height: '100px',
        marginTop: '24px',
        marginLeft: '24px'
    }
}

The nesting could go a little deeper so it needs to be dynamic. Is there a way using lodash or some other library?

2
  • Possible duplicate of Generic deep diff between two objects Commented Feb 16, 2017 at 18:40
  • Thanks. I found a jsfiddle on that page: jsfiddle.net/drzaus/9g5qoxwj It almost does what i need. However it returns empty objects such as this: "diff(a, b) = " {"x":4,"z":{},"zz":{"a":1,"b":2}} "diff(a, b) = " {"x":56,"z":{},"zz":{"a":2,"b":1}}. If I can find a way to remove the z:{} value then it's perfect Commented Feb 17, 2017 at 9:02

2 Answers 2

2

To solve this problem, we must:

  • Create a function that traverses each node in the object recursively. We can achieve this by using the reduce function when traversing the source object.
  • The reduce callback function would first check if the source value or it's other value counter part are both objects. If they are, we'll use these values as arguments to recursively get the difference of both these objects. Otherwise, if they are different, then we'll assign the resulting value from the other value.
  • Lastly, the reduce function accepts a third argument which is used as the initial value for the accumulated of the reduce function. We assign the third argument with key-values from the other object that aren't found in the source object. This is the simplest way to get the newly introduced values from the other object towards the resulting object.

function differenceObjectDeep(source, other) {
  return _.reduce(source, function(result, value, key) {
    if (_.isObject(value) && _.isObject(other[key])) {
      result[key] = differenceObjectDeep(
        value,
        other[key]
      );
    } else if (!_.isEqual(value, other[key])) {
      result[key] = other[key];
    }
    return result;
  }, _.omit(other, _.keys(source)));
}

data.diffObject = differenceObjectDeep(
  data.baseObj,
  data.mergedObject
);

var data = {
  baseObj: {
    image: {
      width: '100%',
      paddingTop: '0px',
      paddingRight: '0px',
      paddingBottom: '0px',
      paddingLeft: '0px'
    },
    wrap: {
      marginTop: '0px',
      marginRight: '0px',
      marginBottom: '0px',
      marginLeft: '0px'
    }
  },
  mergedObject: {
    image: {
      width: '100%',
      paddingTop: '0px',
      paddingRight: '24px', // modified value
      paddingBottom: '24px', // modified value
      paddingLeft: '0px'
    },
    wrap: {
      height: '100px', // new value
      marginTop: '24px', // modified value
      marginRight: '0px',
      marginBottom: '0px',
      marginLeft: '24px' // modified value
    }
  }
};

function differenceObjectDeep(source, other) {
  return _.reduce(source, function(result, value, key) {
    if (_.isObject(value) && _.isObject(other[key])) {
      result[key] = differenceObjectDeep(
        value,
        other[key]
      );
    } else if (!_.isEqual(value, other[key])) {
      result[key] = other[key];
    }
    return result;
  }, _.omit(other, _.keys(source)));
}

data.diffObject = differenceObjectDeep(
  data.baseObj,
  data.mergedObject
);

console.log(data.diffObject);
body>div {
  min-height: 100%;
  top: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.js"></script>

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

Comments

0

you could use recursive function to find the last object.

var checkIfObject = function(item){ //recursive function
_.each(item, function(v, k){
if(_.isObject(v)){
previousObject = k;
previousResult = v;
return checkIfObject(v);
}else{
    finalChildObjects[previousObject] = previousResult;
}
})
return finalChildObjects
}

/*Initialize Values for recursive function*/
var finalChildObjects = {};
var previousObject = '';
var previousResult = '';
baseObjectFinalTurn = checkIfObject(baseObj);
/*Initialize Values for recursive function*/
var finalChildObjects = {};
var previousObject = '';
var previousResult = '';
mergedObjectFinalTurn = checkIfObject(mergedObject);
console.clear();


var difference = {};
_.each(baseObjectFinalTurn, function(v, k){
    if(mergedObjectFinalTurn[k]){
    difference[k] = _.reduce(mergedObjectFinalTurn[k],function(result, value, key){
    if(baseObjectFinalTurn[k][key] != mergedObjectFinalTurn[k][key]){
    result[key] =  value;
    }
    
    return result
    }, {})
    
  }
  else{
  difference[k] = {};
  }
})

console.log(difference)

You can verify the result from this jsfiddle link

Note: you need to adjust the result based on your requirement in reduce. This result is made to match your output.

2 Comments

Thanks for your input. I ran the fiddle and all i see in the console is an object returning true or false. I need it to be the actual different data
Sorry, forgot to update the fiddle. Thanks to fiddle for having the local draft. Here is the updated code jsfiddle.net/yx4ck723/4

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.