1

I'm using gojs library and I have to record which value was modified.(Like Git commit history)

So, I want to compare JSON and detect which key was changed.

Example Original JSON

{
  "key01": {
    "key01-01": "val01-01",
    "key01-02": "val01-02"
  },
  "key02": {
    "key02-01": 0
  }
}

Example Modified JSON

{
  "key01": {
    "key01-01": "val01-01mod"
  },
  "key02": {
    "key02-01": 0,
    "key02-02": 1
    "key02-03": {
      "key02-03-01": 2
    }
  }
}

Compare result

["key01"]["key01-01"] -> modified
["key01"]["key01-02"] -> removed
["key02"]["key02-02"] -> added
["key02"]["key02-03"] -> added
["key02"]["key02-03"]["key-02-03-01"] -> added

Is there a good way to implement this function in javascript?

3
  • Are you trying to determine what changed in the structure? Or, literally trying to compare the serialized version in JSON text? Commented Jun 23, 2021 at 0:46
  • well, first, you want to deal with objects, not JSON - so, parse the JSON to an object - then, it's probably going to need a function written in javascript to do what you want - it'll be quite complex to be honest Commented Jun 23, 2021 at 0:47
  • I'm trying to determine structure, not JSON text. Commented Jun 23, 2021 at 0:53

1 Answer 1

1

You can iterate on object and compare them, I did a naive implementation if you want to take this as a starting point:

const isObject = o => o && typeof o === 'object'
const diffObject = (a, b, prefix = []) => {
    const aKeys = Object.keys(a)
    const bKeys = Object.keys(b)
    const diff = []
    for (const key of aKeys) {
        if (a[key] === b[key]) continue
        if (!(key in b)) {
            diff.push({ type: 'removed', key: [...prefix, key] })
            continue
        }
        if (!isObject(a[key]) || !isObject(b[key])) {
            diff.push({ type: 'modified', key: [...prefix, key] })
            continue
        }
        diff.push(...diffObject(a[key], b[key], [...prefix, key]))
    }
    for (const key of bKeys) {
        if (key in a) continue
        diff.push({ type: 'added', key: [...prefix, key] })
        isObject(b[key]) && diff.push(...diffObject({}, b[key], [...prefix, key]))
    }
    return diff
}

// get the diff
const changes = diffObject({
  "key01": {
    "key01-01": "val01-01",
    "key01-02": "val01-02"
  },
  "key02": {
    "key02-01": 0
  }
}, {
  "key01": {
    "key01-01": "val01-01mod"
  },
  "key02": {
    "key02-01": 0,
    "key02-02": 1,
    "key02-03": {
      "key02-03-01": 2
    }
  }
})

// print the diff formated
for (const change of changes) {
    const formatedKey = change.key.map(k => `[${JSON.stringify(k)}]`).join('')
    console.log(formatedKey, '->', change.type)
}

One of the tricky part is handeling the depth of the object, I kept it in a key array that keeps the history of traversed objects keys.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.