Skip to content

Instantly share code, notes, and snippets.

@Yimiprod
Last active November 1, 2024 06:18
Show Gist options
  • Save Yimiprod/7ee176597fef230d1451 to your computer and use it in GitHub Desktop.
Save Yimiprod/7ee176597fef230d1451 to your computer and use it in GitHub Desktop.
Deep diff between two object, using lodash
/**
* This code is licensed under the terms of the MIT license
*
* Deep diff between two object, using lodash
* @param {Object} object Object compared
* @param {Object} base Object to compare with
* @return {Object} Return a new object who represent the diff
*/
function difference(object, base) {
function changes(object, base) {
return _.transform(object, function(result, value, key) {
if (!_.isEqual(value, base[key])) {
result[key] = (_.isObject(value) && _.isObject(base[key])) ? changes(value, base[key]) : value;
}
});
}
return changes(object, base);
}
@Andrei-Fogoros
Copy link

@Andrei-Fogoros didn't thinked about licence at the time i posted it, but since you're asking, it's a good occasion to put it under MIT License.

Great, thank you very much! :)

@hyunkayhan
Copy link

Not sure if anyone needs this variation, but here's one I made to basically create a separate JSON object with ONLY the changes with accurate child items.

import * as _ from 'lodash';

/**
 * Deep diff between two object-likes
 * @param  {Object} fromObject the original object
 * @param  {Object} toObject   the updated object
 * @return {Object}            a new object which represents the diff
 */
export function deepDiff(fromObject, toObject) {
    const changes = {};

    const buildPath = (path, obj, key) => {
        const origVal = _.get(obj, key);
        if (_.isUndefined(path)) {
            if (_.isArray(origVal)) {
                changes[key] = [];
            } else if (_.isObject(origVal)) {
                changes[key] = {};
            }
        } else {
            if (_.isArray(origVal)) {
                path[key] = [];
            } else if (_.isObject(origVal)) {
                path[key] = {};
            }
        }
        return [_.isUndefined(path) ? changes : path, key]
    }
        

    const walk = (fromObject, toObject, path) => {
        for (const key of _.keys(fromObject)) {
            const objKeyPair = buildPath(path, fromObject, key);
            if (!_.has(toObject, key)) {
                objKeyPair[0][objKeyPair[1]] = { from: _.get(fromObject, key) };
            }
        }

        for (const [key, to] of _.entries(toObject)) {
            const isLast = _.has(fromObject, key);
            const objKeyPair = buildPath(path, fromObject, key);
            if (isLast) {
                const from = _.get(fromObject, key);
                if (!_.isEqual(from, to)) {
                    if (_.isObjectLike(to) && _.isObjectLike(from)) {
                        walk(from, to, objKeyPair[0][objKeyPair[1]]);
                    } else {
                        objKeyPair[0][objKeyPair[1]] = { __old: from, __new: to };
                    }
                } else {
                    delete objKeyPair[0][objKeyPair[1]]
                }
            } else {
                objKeyPair[0][objKeyPair[1]] = { to };
            }
        }
    };

    walk(fromObject, toObject);

    return changes;
}

@jfortez
Copy link

jfortez commented Mar 1, 2024

ty

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment