wbish / jsondiffpatch.net

JSON object diffs and reversible patching (jsondiffpatch compatible)
MIT License
371 stars 83 forks source link

Is there an equiv to propertyFilter to filter out properties? #34

Closed DanaEpp closed 3 years ago

DanaEpp commented 4 years ago

When conducting a diff between two objects, they will always have different timestamps (a key property in our object). Is there a way to conduct a diff ignoring that field?

In jsondiffpatch there is a propertyFilter function you can override that would allow you to ignore a property. Does that exist in jsondiffpatch.net?

wbish commented 4 years ago

Nothing like that exists today -- it would be great feature to add.

DanaEpp commented 4 years ago

Thanks for the fast response. I'd sponsor that feature if anyone wants to step up and submit a pull request for it. I don't have the cycles right now or I would do it myself.

RyanObray commented 4 years ago

+1 on this one. I'm working with JSON objects in a CosmosDb store and I'd like to to be able to ignore the system properties that get tacked onto document records. It'd also facilitate the ability to create a property based rules engine to prevent systems from changing properties that they don't own. Being able to leverage the "JsonDiffPatch" "Options" parameter like this would be awesome:

Ignore Paths Option (Example)

var excludePaths = new List<string>() {"sensitive.ssn","_rid", "_self", "_etag", "_attachments", "_ts"};
var diffPatch = new JsonDiffPatch(new Options() { ExcludePaths=excludePaths });
//Illustrating applying diff patch from here on down but the two lines above illustrate the point of how this could be usefully specified
var currentDoc = JToken.Parse(currentDocJson);
var updateDoc = JToken.Parse(updateDocJson);
var patch = diffPatch.Diff(currentDoc, updateDoc);
var updatedDocument = diffPatch.Patch(currentDoc, patch);
var deltaFormatter = new JsonDeltaFormatter();
var operations = JsonConvert.SerializeObject(deltaFormatter.Format(patch), Formatting.None);
log.LogInformation($"DocumentId=\"{documentId}\", CorrelationId=\"{correlationId}\", PatchDetails=\"{operations}\"");

Another alternative (or addition all together) that I'd find SUPER useful would be an option to ONLY apply value changes for the properties that were defined in the update JSON. I realize that updating get's really tricky because you have to decide whether or not to ignore new properties or add them or ignore missing properties or delete them. I have a lot of use cases where different properties are owned by different systems and instead of doing inheritance backflips it'd be great if the consuming applications could only supply what needs to change (because it's unlikely they'd have the entire document anyway). Maybe another "Options" enum (maybe annotated with [Flags] so multiple options can be specified) with options like "IgnoreNewProperties", "IgnoreMissingProperties" and whatever else makes sense. Here's some example to better illustrate the idea (combining ideas):

Diff Behavior Option (Example)

//currentDocJson input: { "id":"1", "firstName":"John",  "lastName":"Doe", "emailAddress":"john.doe@myco.com" }
//updateDocJson input: { "lastName":"Dozer" }

var diffPatch = new JsonDiffPatch(new Options() { DiffBehavior=Behavior.IgnoreMissingProperties});
var currentDoc = JToken.Parse(currentDocJson);
var updateDoc = JToken.Parse(updateDocJson);
var patch = diffPatch.Diff(currentDoc, updateDoc);
var updatedDocument = diffPatch.Patch(currentDoc, patch);

//updatedDocument output: { "id":"1", "firstName":"John", "lastName":"Dozer", "emailAddress":"john.doe@myco.com" }

Combination of Both Suggestions (Example)

//currentDocJson input: { "id":"1", "firstName":"John",  "lastName":"Doe", "emailAddress":"john.doe@myco.com" }
//updateDocJson input: { "id":"2", "lastName":"Dozer", "ssn":"111-22-3333" }

var excludePaths = new List<string>() {"id"};
var diffPatch = new JsonDiffPatch(new Options() { ExcludePaths=excludePaths , DiffBehavior=Behavior.IgnoreMissingProperties | Behavior.IgnoreNewProperties });
var currentDoc = JToken.Parse(currentDocJson);
var updateDoc = JToken.Parse(updateDocJson);
var patch = diffPatch.Diff(currentDoc, updateDoc);
var updatedDocument = diffPatch.Patch(currentDoc, patch);

//updatedDocument output: { "id":"1", "firstName":"John",  "lastName":"Dozer", "emailAddress":"john.doe@myco.com" }
//Note that:
//- "id" was ignored because of the ignorePaths filter
//- no existing properties were deleted because of the "IgnoreMissingProperties" flag (don't delete properties from the current doc json that aren't specified in the update json...partial update)
//- "ssn" was ignored because of the "IgnoreNewProperties" behavior flag

It's possible that this suggestion doesn't align with the RFC standards but admittedly I'm no expert on the standards so this suggestion is coming from the angle of trying to find a solution to a problem.