mattphillips / deep-object-diff

Deep diffs two objects, including nested structures of arrays and objects, and returns the difference. ❄️
https://www.npmjs.com/package/deep-object-diff
MIT License
1.05k stars 89 forks source link

[Feature request] Add filter #53

Open SergeyPirogov opened 4 years ago

SergeyPirogov commented 4 years ago

In order to compare objects, I want to filter some keys. For example:

lhs = {
"name": "a",
"phone": "b"
}

rhs = {
"name": "a",
"phone": "c"
}

diff(lhs, rhs, function filter(node){
   return node.name === 'phone'
})
anko commented 4 years ago

What would the diff call in your example code return? I don't understand yet what "filter" means in this context.

SergeyPirogov commented 4 years ago

@anko objects will be equal because we ignore phone node

anko commented 4 years ago

I see!

I played with some possible workarounds in this Observable notebook trying to see if any of them sound good. Performance-wise, none of them would be as good as having a filter function parameter like this. (Have you tried the alternatives, and found the performance to be a problem?)

Perhaps we should pre-empt all similar future queries by letting the passed-in function instead implement completely custom comparison. Ignoring some property is just a subset of that power:

diff(lhs, rhs, function compare(left, right, propertyName, defaultCompare) {
  // Compare all properties as normal, except `phone`, which always
  // compares as equal.
  if (propertyName === "phone") return true
  else return defaultCompare(left, right, propertyName)
})

That way when someone asks for e.g. case-insensitive string diff, or filtering a property except when null, or things like that, they can implement any such logic.

papb commented 4 years ago

@anko That sounds great!!

SergeyPirogov commented 4 years ago

You can look at some similar library. They have similar filter https://www.npmjs.com/package/deep-diff#changes

k-funk commented 3 years ago

+1

I've come across this deep-object-diff lib in the past few years, hoping to find a lib that does everything this one does, plus filtering. I usually end up writing my own diff, since I find the deep-diff lib that @SergeyPirogov mentioned to be overkill.

I'd prefer the simple key-based filtering api like the one suggested: diff(lhs, rhs, key => key === 'phone'), which is similar to Array.prototype.filter usage. If true, skip comparison+further recursion early. But I'd be amenable to returning defaultCompare if necessary.

Also, while I haven't personally had a use for comparing values, I could see how this "fitler" could also be used for custom comparisons, which might be useful if you wanted to compare Dates, or other complex objects.


FWIW, the most common object-diffing usage for me is doing a restful HTTP PATCH that would look something like this:

const PROPS_TO_ALWAYS_INCLUDE = ['id', 'mode'] // could be other identifying keys like 'objectId' or 'mode'

async function patchToServer(urlPath, left, right) {
  const payload = diff(left, right, key => PROPS_TO_ALWAYS_INCLUDE.includes(key))
  await ServerCall(urlPath, 'PATCH', payload)
}

...

patchToServer('/users/user_123', originalData, userModifiedData)
rdsedmundo commented 3 years ago

Also needing this for another use case: ignore word casing.