シナリオ:2つのJSONオブジェクトを比較し、違いのリストと、可能であればカバレッジメトリックなどのデータを含むJSONオブジェクトを返す関数が必要です。
_var madrid = '{"type":"team","description":"Good","trophies":[{"ucl":"10"}, {"copa":"5"}]}';
var barca = '{"type":"team","description":"Bad","trophies":[{"ucl":"3"}]}';
_
compare(madrid, barca)
を実行した場合、返されるオブジェクトは次のようになります。
_{"description" : "Bad", "trophies":[{"ucl":"3"}, {"copa":"5"}]};
_
または似たようなもの、あなたはアイデアを得る。
誰もがこれに対する解決策を知っていますか? plugin をすでに見つけていますが、他に選択肢があるかどうか知りたいです。
オブジェクトキーで反復する再帰関数を使用することが可能です。次に、 Object.is を使用して、NaN
およびnull
をテストします。次に、2番目のオブジェクトが、0
、false
、またはNaN
のようなnull
にキャストするタイプかどうかをテストします。両方のオブジェクトのキーをリストし、それらを連結してobj1
の欠落キーをテストし、それを繰り返します。
同じキー値に違いがある場合、object2
の値を保存して続行します。両方のキー値がオブジェクトである場合、再帰的に比較できることを意味します。
function diff(obj1, obj2) {
const result = {};
if (Object.is(obj1, obj2)) {
return undefined;
}
if (!obj2 || typeof obj2 !== 'object') {
return obj2;
}
Object.keys(obj1 || {}).concat(Object.keys(obj2 || {})).forEach(key => {
if(obj2[key] !== obj1[key] && !Object.is(obj1[key], obj2[key])) {
result[key] = obj2[key];
}
if(typeof obj2[key] === 'object' && typeof obj1[key] === 'object') {
const value = diff(obj1[key], obj2[key]);
if (value !== undefined) {
result[key] = value;
}
}
});
return result;
}
上記のコードはBSDライセンスであり、どこでも使用できます。
テストリンク: https://jsfiddle.net/gartz/vy9zaof2/54/
重要な観察、これは配列をオブジェクトに変換し、同じインデックス位置の値を比較します。複雑さが必要なため、この関数でカバーされない配列を比較する方法は他にもたくさんあります。
EDIT 2/15/2019:この回答は、新しいES2017構文を追加し、コメントからのユースケースを修正するために変更されました。
これは単なるキックオフであり、まだテストしていませんが、フィルターまたはコンパレーター機能から始めました。これは再帰的であり、優先結果を取得する必要がある場合は変更します。
function filter(obj1, obj2) {
var result = {};
for(key in obj1) {
if(obj2[key] != obj1[key]) result[key] = obj2[key];
if(typeof obj2[key] == 'array' && typeof obj1[key] == 'array')
result[key] = arguments.callee(obj1[key], obj2[key]);
if(typeof obj2[key] == 'object' && typeof obj1[key] == 'object')
result[key] = arguments.callee(obj1[key], obj2[key]);
}
return result;
}
Rus-diff https://github.com/mirek/node-rus-diff を使用して、MongoDB互換(rename/unset/set)diffを作成できます。
// npm install rus-diff
var madrid = {"type":"team","description":"Good","trophies":[{"ucl":"10"}, {"copa":"5"}]};
var barca = {"type":"team","description":"Bad","trophies":[{"ucl":"3"}]};
var rusDiff = require('rus-diff').rusDiff
console.log(rusDiff(madrid, barca))
出力:
{ '$unset': { 'trophies.1': true },
'$set': { description: 'Bad', 'trophies.0.ucl': '3' } }
gabriel Gartzのバージョンへの私の変更の貢献。これは厳密モードで動作し、配列チェックを削除します-常にfalseになります。また、空のノードを差分から削除します。
//http://stackoverflow.com/questions/679915/how-do-i-test-for-an-empty-javascript-object
var isEmptyObject = function(obj) {
var name;
for (name in obj) {
return false;
}
return true;
};
//http://stackoverflow.com/questions/8431651/getting-a-diff-of-two-json-objects
var diff = function(obj1, obj2) {
var result = {};
var change;
for (var key in obj1) {
if (typeof obj2[key] == 'object' && typeof obj1[key] == 'object') {
change = diff(obj1[key], obj2[key]);
if (isEmptyObject(change) === false) {
result[key] = change;
}
}
else if (obj2[key] != obj1[key]) {
result[key] = obj2[key];
}
}
return result;
};