JSON diff and merge (JavaScript)

Recently i had a scenario where angular and react based forms were storing data in a single field (multiline plain text field in a SharePoint list storing stringified JSON data). I needed to make it possible for multiple users to edit different parts of the form at the same time but this would mean if two people opened the form, person 1 saves and then person 2 saves – the second save would over-write the first person’s save even if they only changed one field.

To handle this scenario, i needed a generic way to find all edits made by the user and then at save time, merge those edits into the latest version of the data on the server as follows:

  • User opens form and changes some fields. This changes the JSON data model. The user clicks save.
  • Resolve the changes made to the data model by the user
  • Fetch the latest version of the data from SharePoint
  • Merge edits into the latest server version of the data
  • Save the data to SharePoint. Handle save conflicts by retrying this process (CSOM/JSOM will always throw an exception on save conflict, or use etag if using REST)

This was originally implemented as an Azure API (C#) and later ported to javascript and used directly in forms.

I created this API (JsonDiffMerge) to handle this scenario by producing a JSON object representing the changes made to JSON (differences), and with the ability to merge this diff object into JSON data. It handles deep json and arrays of objects (primary key identifies objects in arrays – “id”, “uid” or “date”), and can add / edit / delete array objects. Merging is similar to the PowerApps patch function (but works on deep objects, not just flat).

.

JsonDiffMerge

Light / simple API for JSON diff and merge.

Features:

  • jsonDiff: Get the difference between two json objects in JSON (in a format that can be used by the mergeJson function). This is a deep diff.
    • Deep diff, handles nested objects
    • Handles arrays of objects (objects in arrays must have a primary key (string) attribute: “id”, “uid” or “date” are the defaults; you can pass mappings for a custom primary key
  • mergeJson: Merge edits into a JSON object.

Example 1: get the edits made to json data:

Example 2: merge edits into json object

Example 3: Merge or patch some custom edits into a json object

Full solution code

Leave a comment