-
-
Save Yimiprod/7ee176597fef230d1451 to your computer and use it in GitHub Desktop.
/** | |
* 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); | |
} |
Here is an update of @Chippd with specifics paths
`
function deepDiff(fromObject, toObject, specificPaths) {
const changes = {};
console.log('specificPaths:', specificPaths);
const buildPath = (path, __, key) =>
_.isUndefined(path) ? key : `${path}.${key}`;
let obj1 = {};
let obj2 = {}
if (_.isArray(specificPaths) && !_.isEmpty(specificPaths)) {
for (const path of specificPaths) {
if (_.has(fromObject, path)) {
_.set(obj1, path, _.get(fromObject, path));
} else if (_.has(toObject, path)) {
changes[path] = {to: _.get(toObject, path)};
}
if (_.has(toObject, path)) {
_.set(obj2, path, _.get(toObject, path));
} else if (_.has(fromObject, path)) {
changes[path] = {from: _.get(fromObject, path)};
}
}
} else {
obj1 = fromObject
obj2 = toObject
}
const walk = (fromObject, toObject, path) => {
for (const key of _.keys(fromObject)) {
const currentPath = buildPath(path, fromObject, key);
if (!_.has(toObject, key)) {
changes[currentPath] = { from: _.get(fromObject, key) };
}
}
for (const [key, to] of _.entries(toObject)) {
const currentPath = buildPath(path, toObject, key);
if (!_.has(fromObject, key)) {
changes[currentPath] = { to };
} else {
const from = _.get(fromObject, key);
if (!_.isEqual(from, to)) {
if (_.isObjectLike(to) && _.isObjectLike(from)) {
walk(from, to, currentPath);
} else {
changes[currentPath] = { from, to };
}
}
}
}
};
walk(obj1, obj2);
return changes;
}
const previousValue = {
customisations: {
localeOverrides: {
foo: 1,
},
bar: 2
},
bar: [1,2,3],
onboarding: {
foo: 1
},
foo: 1
}
const newValue = {
customisations: {
localeOverrides: {
daz: 1,
},
bar: 2,
daz: 2
},
onboarding: {
foo: 4
},
baz: 2
}
const changes = deepDiff(previousValue, newValue, [
"customisations",
"customisations.localeOverrides",
"onboarding"
]);
// Only specific path
const changes2 = deepDiff(previousValue, newValue, [
"customisations.localeOverrides",
"bar"
]);
// test only if validate that array is present and isn't empty
const changes3 = deepDiff(previousValue, newValue, []);
// no array present
const changes4 = deepDiff(previousValue, newValue);
console.log('compare result various paths', changes);
console.log('compare result Only specific path', changes2);
console.log('compare result test only if validate that array is present and isn't empty', changes3);
console.log('compare result no array present', changes4);
`
Just one example works fine in my case (shallow diff):
const diffData = _.fromPairs( _.differenceWith(_.toPairs(sourceData), _.toPairs(valuesToDiffWith), _.isEqual), )
any suggestions for deep diff?
thank you, it helps me and makes me look prop :). lodash is superbe
Just another shallow diff
const shallowDiff = Object.entries(object1).reduce(
(diff, [key, value]) =>
_isEqual(object2[key], value) ? diff : { ...diff, [key]: value },
{},
)
@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.
@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! :)
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;
}
ty
Sharing my own update - I needed to only compare some top-level properties of two objects, so added an optional third parameter to take an array of paths to specifically check.