flitbit / diff

Javascript utility for calculating deep difference, capturing changes, and applying changes across objects; for nodejs and the browser.
MIT License
2.99k stars 213 forks source link

Work with array of objects #100

Open NewOldMax opened 7 years ago

NewOldMax commented 7 years ago

Hi, In my case, I have some array of objects ordered by name key. This code

var lhs = [{id: 1, name: "a"}, {id: 2, name: "b"}, {id: 3, name: "c"}]; // old array, given from backend previous time
var rhs = [{id: 2, name: "b"}, {id: 3, name: "c"}, {id: 1, name: "e"}]; // new array, git from backend now

deepDiff(lhs, rhs);

says that I have 6 changes, but in real only 1 object is changed {id: 1, name: "e"}. Is there a way to get something like "1 edition in {id: 1, name: "e"}"? I want to use it for a making new items for user, like "hey, this item has been changed". Can I achieve this with your library?

tarekz commented 7 years ago

I have the same problem when I delete the first element of an array. It creates n differences for an array of n elements.

var lhs =  ["1", "2", "3", "4"]; // old array, given from backend previous time
var rhs = ["2", "3", "4"];// new array, git from backend now

deepDiff(lhs, rhs);

result:

[{
    "kind": "E",
    "path": [0],
    "lhs": "1",
    "rhs": "2"
}, {
    "kind": "E",
    "path": [1],
    "lhs": "2",
    "rhs": "3"
}, {
    "kind": "E",
    "path": [2],
    "lhs": "3",
    "rhs": "4"
}, {
    "kind": "A",
    "index": 3,
    "item": {
        "kind": "D",
        "lhs": "4"
    }
]

I just think it should return [{"kind": "A","index": 0,"item": {"kind": "D","lhs": "1"}]

vincentsels commented 6 years ago

I think the solution could be to, instead of always comparing items in both arrays index-by-index, provide an option to pass a function which specifies how to compare items within an array by some kind of unique identifier or hash. Typically this will just be item => item.id (as in the first given example) or even just item => item (second example).

When such a function is supplied, it would be used to detect whether an item in one array exists in the other. Note that if it does and it is an object (or other array), these objects themselves still need to be compared because they might have other changes.

When the function is not supplied, the current index-by-index comparison can still be used as fallback.

pschaub commented 6 years ago

@vincentsels I agree with your idea. We need a function to tell the library how to compare objects (e.g. by item.id of each object instead of the array key).

Is there any workaround yet or do we need to wait for a PR?

NewOldMax commented 6 years ago

@pSchaub I'm using something like this (one level diff)

import deepDiff from 'deep-diff';

function arrayCompare(arrFirst, arrSecond, propName) {
    const arrDiff = [];
    let fields;
    let obj;
    for (let key2 in arrSecond) {
        obj = arrFirst.filter(o => o[propName] === arrSecond[key2][propName]);
        obj = obj[0];
        if (obj !== undefined) {
            fields = deepDiff(obj, arrSecond[key2]);
        }
        if (fields !== undefined) {
            arrDiff.push({ key: key2, fields });
        }
    }
    if (arrDiff.length) {
        return arrDiff;
    }
    return false;
}

const diff = arrayCompare(firstArr, secondArr, 'id');
pschaub commented 6 years ago

btw: this issue is a duplicate, see #37

pschaub commented 6 years ago

@NewOldMax But your solution will not work with nesting (e.g. array > object > array > object > ..), right?

NewOldMax commented 6 years ago

Didn't test with nested, in my cases I have only first-level differences

pschaub commented 6 years ago

@NewOldMax I don't see any kind of recursion in your code so this shouldn't work in nested situations. We really need a fix inside the library itself. But thanks for your workaround for 1st-level-differences.

kenberkeley commented 6 years ago

any progress?

pschaub commented 6 years ago

@kenberkeley We switched to https://github.com/benjamine/jsondiffpatch to solve our nested situation. Maybe this will help you until anybody will implement a way into this package.

kingasare commented 5 years ago

Any updates in regards to this issue.