flitbit / diff

Javascript utility for calculating deep difference, capturing changes, and applying changes across objects; for nodejs and the browser.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Work with array of objects

NewOldMax opened this issue · comments

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?

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"}]

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.

@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?

@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');

btw: this issue is a duplicate, see #37

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

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

@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.

any progress?

@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.

Any updates in regards to this issue.