deep-object-diff icon indicating copy to clipboard operation
deep-object-diff copied to clipboard

[Feature request] Add filter

Open SergeyPirogov opened this issue 5 years ago • 7 comments

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'
})

SergeyPirogov avatar Jan 06 '20 10:01 SergeyPirogov

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

anko avatar Jan 07 '20 14:01 anko

@anko objects will be equal because we ignore phone node

SergeyPirogov avatar Jan 07 '20 15:01 SergeyPirogov

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.

anko avatar Jan 07 '20 21:01 anko

@anko That sounds great!!

papb avatar Jan 07 '20 21:01 papb

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

SergeyPirogov avatar Jan 08 '20 06:01 SergeyPirogov

+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)

k-funk avatar May 11 '21 05:05 k-funk

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

rdsedmundo avatar Aug 22 '21 20:08 rdsedmundo