2017-10-19 131 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',這會將對象鍵檢索爲一個數組列表.. –