Compare Nested Objects and save difference in new object using Javascript

Viewed 1316

I have two Javascript objects

var order1 = {
    sandwich: 'tuna',
    chips: true,
    drink: 'soda',
    order: 1,
    toppings: [{VendorNumber: 18, PreferredFlag: false, SupportedFlag: true}, {VendorNumber: 19, PreferredFlag: false, SupportedFlag: true}, {VendorNumber: 20, PreferredFlag: false, SupportedFlag: true}],
    details: {
        name: 'Chris',
        phone: '555-555-5555',
        email: 'no@thankyou.com'
    },
    otherVal1: '1'
};

var order2 = {
    sandwich: 'turkey',
    chips: true,
    drink: 'soda',
    order: 2,
    toppings: [{VendorNumber: 18, PreferredFlag: false, SupportedFlag: true}, {VendorNumber: 19, PreferredFlag: false, SupportedFlag: false}, {VendorNumber: 20, PreferredFlag: true, SupportedFlag: true}],
    details: {
        name: 'Jon',
        phone: '(555) 555-5555',
        email: 'yes@please.com'
    },
    otherVal1: '2'
};

What I need is to compare these two objects (order1 is existing and order2 is the edited data) and store the difference in a new variable named var order3. However if there is an array inside an object like the toppings array to be copied as whole with the changes.

In short the result should be

{
  details: {
    email: "yes@please.com",
    name: "Jon",
    phone: "(555) 555-5555"
  },
  order: 2,
  otherVal1: "2",
  sandwich: "turkey",
  toppings: [{
  PreferredFlag: false,
  SupportedFlag: true,
  VendorNumber: 18
}, {
  PreferredFlag: false,
  SupportedFlag: false,
  VendorNumber: 19
}, {
  PreferredFlag: true,
  SupportedFlag: true,
  VendorNumber: 20
}]
}

How can i achieve this ?

2 Answers

This gives you exactly what you wanted:

function diff(tgt, src) {

    if (Array.isArray(tgt)) { // if you got array
        return tgt; // just copy it
    }

    // if you got object
    var rst = {};
    for (var k in tgt) { // visit all fields
        if (typeof src[k] === "object") { // if field contains object (or array because arrays are objects too)
            rst[k] = diff(tgt[k], src[k]); // diff the contents
        } else if (src[k] !== tgt[k]) { // if field is not an object and has changed
            rst[k] = tgt[k]; // use new value
        }
        // otherwise just skip it
    }
    return rst;
}
console.log(diff(order2, order1));

I think you are looking for a diff'ing algorithm. Wrote this quick recursive function that iterates over each enumerable property of your JavaScript object (not json object) testing equality. Note that the position of arguments does affect the output

function diff(obj1, obj2) {
    if (typeof obj1 === "object") {
        const obj = {};
        for (const prop in obj1) {
            if (diff(obj1[prop], obj2[prop])) {
                obj[prop] = obj1[prop]
            }
        }
        return obj
    } else {
        return obj1 !== obj2;
    }
}

console.log(diff(order2, order1))
Related