1

I have done some work to do a deep comparison (via Underscore and diff) between two objects (actually a pre-save and post-save version of the same document) in order to isolate the section that is different after a save. Take this document structure as an example:

{
   _id: 4d39fe8b23dac43194a7f571,
   name: {
     first: "Jane",
     last: "Smith"
   }
   services: [
    {
     service: "typeOne",
     history: [ 
       { _id: 121, 
         completed: true,
         title: "rookie"
       },
       { _id: 122, 
         completed: false,
         title: "novice"
       } 
      ]
     },
     {
      service: "typeTwo",
      history: [ 
       { _id: 135, 
         completed: true,
         title: "rookie"
       },
       { _id: 136, 
         completed: false,
         title: "novice"
       } 
      ]
     }
   ]
 }

If a new element is added to the history array I'm able to successfully parse out that change.

However, in addition to pulling out this changed section, I also want to be able to effectively walk up from history in order to find the value for service, because I also need to know which of the two services array elements actually changed. Is there a way I can do this with native es6 JavaScript?

If not, is there a library I can use to determine this? Right now I'm able to get the value for "service" via indexing:

if (diff.path[1] === 0) {
  targetService = "typeOne";
} else if (diff.path[1] === 1) {
  targetService = "typeTwo";
} else if (diff.path[1] === 2) {
  targetService = "typeThree";
}

But from my understanding this isn't full proof, because there's no guarantee the order of elements within "services" couldn't change at some point. I suppose this indexing method could work if I could enforce the ordering of the elements within the services array. I'm just not sure if there's a way to do that (open to suggestions if it is possible).

Muirik
  • 6,049
  • 7
  • 58
  • 116
  • This is a serialization of a document tree, it's not an actual tree (in which nodes would have a `parent` reference). Parse it, don't use it like this. If you're looking for native document trees, write your document as XML, parse it in the browser with DOMParser and boom! you get a native document tree with a rich tree navigation API. – Touffy Feb 12 '19 at 13:41
  • Okay, without getting too focused on the document-tree language, and without doing a major re-factor, is there a way I can determine the value for `service` when I know which embedded `history` element changed? – Muirik Feb 12 '19 at 13:44
  • It's not about language, it's about the notion of a document **tree**. If you want tree-like properties, you need to parse your document into a tree. You can either do this once and monitor for changes (as the MutationObserver DOM API would do natively) or parse it **every time** you want a parent lookup if you don't want to store the tree. – Touffy Feb 12 '19 at 13:46
  • I guess from your question that you don't have the choice of detecting mutations on your document since you're working on saved serializations (do you have to?). I can't think of any native JavaScript that does a diff like that. Sorry. – Touffy Feb 12 '19 at 13:52

1 Answers1

2

deep-diff gives you the path to this change, something like this:

{
    kind: 'N',
    path: ['services', 1, 'history'],
    // ... other properties
}

You can use this path to track the changed object:

tree.services[changes.path[1]].service // 'typeTwo'
NemoStein
  • 2,088
  • 2
  • 22
  • 36
  • 1
    ... or if you want to access it dynamically: https://stackoverflow.com/a/54526217/1814486 – nicholaswmin Feb 12 '19 at 13:49
  • @NemoStein, nice! I was hoping `deep-diff` had this kind of functionality. I just couldn't find it, so I was using indexing on that "1" you have in your example. – Muirik Feb 12 '19 at 13:49
  • @NikKyriakides Nice reference! Using reduce to travel the path is very clever! +1 there ;D – NemoStein Feb 12 '19 at 13:52