2017-10-19 187 views
1

所以我有这样的场景,我有一个客户端应用程序它发送数据(对象数组)到服务器,然后将数据转发到其他客户连接到这台服务器。JavaScript数组和对象:获得差异,合并它们

客户端应用程序,该数据是不断变化的,意思是:值的变化,在阵列内的新对象弹出,被删除的对象,等等...

现在我想的其他客户端总是收到最新的数据。而且因为我不想让客户端应用程序只是推全新的数据,然后其他客户转发全新的数据服务器,我决定让客户端应用程序只推变化(使用此库:https://www.npmjs.com/package/deep-object-diff)。

其他客户然后接收对象的数组,只有已实际上改变因为他们知道以前的数据阵列,我希望他们能“合并”变化的阵列与旧的数据对象的数据。

我的实际问题是合并。我不知道如何正确地做到这一点。特别是如果我有一个对象的数组没有任何关键的对象。

所以我的数据看起来是这样的:

let data = [ 
    { 
    name: 'Peter', 
    age: 26, 
    sID: 546589995544 
    }, 
    { 
    name: 'John', 
    age: 33, 
    sID: 554589525469 
    } 
]; 

其实还有更多,但很好,这就是结构。

因此,如果比较库说,这是改变:

let changes = { 
    { 
    age: 34, 
    sID: 554589525469 
    } 
}; 

(请注意,我现在有对象的对象,而不是对象的数组那是什么的DIFF库的回报。)

我想合并的对象是

[ 
    { 
    name: 'Peter', 
    age: 26, 
    sID: 546589995544 
    }, 
    { 
    name: 'John', 
    age: 34, 
    sID: 554589525469 
    } 
]; 

(约翰现在是一岁)

所以我完全相信,如果我将对象的关键字作为标识符,这会容易得多,但我仍然认为必须为此场景提供解决方案。正如你所看到的,财产可以作为一个标识符,它只是一个关键。

我会apprectiate如果有人能指出如何做,在这两种情况下(有和没有对象特定键)

+0

合并相同ID的数据见https://stackoverflow.com/help/mcve – guest271314

+0

现在你的问题的代码无效... –

回答

1

您可以使用.find()找到数组中的对象其中值应该改变,Object.assign()设定值

let data = [{ 
 
    name: 'Peter', 
 
    age: 26, 
 
    sID: 546589995544 
 
    }, 
 
    { 
 
    name: 'John', 
 
    age: 33, 
 
    sID: 554589525469 
 
    } 
 
]; 
 

 
let changes = [{ 
 
    age: 34, 
 
    sID: 554589525469 
 
}]; 
 

 
for (let prop of changes) { 
 
    let {sID} = prop; 
 
    Object.assign(data.find(({sID: id}) => id === sID), prop) 
 
} 
 

 
console.log(data);

+0

看起来像一个不错的方法,这有点作品。它不适用于我,因为diff-library不会返回一个对象数组,而是一个包含对象作为成员的对象。然后,您的解决方案不再有效,因为更改[Symbol.iterator]不是函数。任何解决这个问题? – SVARTBERG

+1

您可以使用Object.values()或Object.entries()将对象转换为属性值对的数组数组。为什么你没有在代码中包含实际使用的对象? – guest271314

+0

我的错,谢谢。写这个问题时没有考虑它。所以你认为我应该再次将变化转换为一个对象数组?我需要研究如何用你的建议功能来实现这一点。谢谢。 – SVARTBERG

1

你可以使用一个SID地图快速查找:

const byId = new Map(data.map(el => [el.sID, el])); 

那么对于每一个变化,我们可以发现,如果与obj已经存在,如果不是我们添加它,如果是的,我们变异:

changes.forEach(change => { 
const res = byId.get(change.sID); 
if(res){ 
    Object.assign(res, change); 
}else{ 
    data.push(change); 
    byId.set(change.sID, change); 
} 
}); 
+0

什么是您的数据?并且在评论中发现类似于@svartberg的guest271314 – SVARTBERG

+0

答案的相同问题,这是基于* your * code的。 –

+0

哦,对不起,没有得到你的代码重写旧数据对象的事实。非常感谢。要做一些更多的测试 – SVARTBERG

1

使用lodash,你可以用unionBy做到这一点:

const newData = _.unionBy(changes, data, 'sID'); // values from changes will be picked 

这将挑选来自基于阵列的对象在sID上,并将它们组合成单个阵列。

+0

Works,直到一个新的对象被添加到初始数据。 – SVARTBERG

+0

@SVARTBERG当添加一个新对象时,再次运行unionBy。 – Fawaz

1

如果更改数据object of objects,你可以使用Object.values循环的数据值,并通过Object.assign

let data = [ 
    { 
    name: 'Peter', 
    age: 26, 
    sID: 546589995544 
    }, 
    { 
    name: 'John', 
    age: 33, 
    sID: 554589525469 
    } 
]; 

let changes = { 
    0: 
    { 
    age: 34, 
    sID: 554589525469 
    } 
}; 

data.filter((idx,i)=> 
    Object.values(changes).forEach((index)=> 
     (index.sID == idx.sID) ? Object.assign(data[i],index) : null 
     ) 
); 
console.log(data); 
+0

感谢您的回答。迄今为止工作。你能告诉我它是如何工作的,如果我有和每个对象的键的对象,而不是一个具有唯一标识符的新字段? – SVARTBERG

+0

我想你可以使用'Object.keys',这会将对象键检索为一个数组列表.. –