mattphillips / deep-object-diff

Deep diffs two objects, including nested structures of arrays and objects, and returns the difference. ❄️
https://www.npmjs.com/package/deep-object-diff
MIT License
1.05k stars 89 forks source link

Arrays are being transformed into objects #14

Closed rbrlortie closed 7 years ago

rbrlortie commented 7 years ago

When running deep-object-diff on an object which contains arrays those arrays are turned into objects.

Object on which deep-object-diff is used:

{
    "Order": [{
        "OrderLines": [{
            "canEditQty": true,
            "ProductId": "1234",
            "ProductCode": "sku-1234",
            "QtyAvailable": "5",
            "QtyOrdered": "5",
            "QtyInvoiced": "0",
            "QtyShipped": "5",
            "QtyInitialBo": "0",
            "QtyBo": "0",
            "Total": 6.8,
            "Price": 1.36,
            "PriceText": "$1.36",
            "PriceMatchStatus": 0,
            "OriginalPrice": 1.36,
            "OriginalPriceText": "$1.36",
            "IsPriceMatch": false
        }]
    }]
}

Those values are changed to : QtyOrdered: "7" Total: "9.52" Price: "1.36"

Result of deep-object-diff:

{
    "Order": {
        "0": {
            "OrderLines": {
                "0": {
                    "QtyOrdered": "7",
                    "Total": "9.52",
                    "Price": "1.36"
                }
            }
        }
    }
}

This creates issues where we expect some data to be arrays and they are now objects.

williamboman commented 7 years ago

Having the same problem.

Here's an (untested, semi-pseudo coded) work-around (will only handle array at root level in the object).

import {diff as _diff} from 'deep-object-diff'

function diff(obj1, obj2) {
    const arrays = Object.keys(obj1).filter(k => Array.isArray(obj1[k]))
    const res = _diff(obj1, obj2)
    Object.keys(res).filter(k => arrays.includes(k)).forEach(k => res[k] = obj2[k])
    return res
}
mattphillips commented 7 years ago

Hey sorry for the delay in replying @rbrlortie @williamboman - thanks for raising the issue.

The problem around arrays is a tough one because of the context of an index. When diffing an array an item may have been updated, removed or added. The way these differences are represented is by preserving the value as an object with the original indexes for the items that have differences.

For example inserting into the start of an array will cause all entries to have been updated and the last to appear to have been added.

Ideally if it is possible any additional preservation of an array should happen outside of the diff function. deep-object-diff will provide the differences in two data structures and then the consumer can chose to do something with these difference a bit like @williamboman's example.

I hope what I have said makes sense and helps. Let me know if you need any more help :smile:

williamboman commented 7 years ago

@mattphillips That makes total sense, it's definitely out of scope for this project. I might open-source a solution to this as a separate package in the future (that essentially wraps this module but completely disregards arrays from the diffing algo).

mattphillips commented 7 years ago

@rbrlortie @williamboman I'm going to close this, let me know if you need anymore help :smile: