获得两个json对象的差异

时间:2011-12-08 13:22:34

标签: javascript jquery json diff

场景:我想要一个比较两个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,但我想知道是否有其他选择。

5 个答案:

答案 0 :(得分:28)

可以使用通过对象键迭代的递归函数。然后使用Object.is来测试NaNnull。然后测试第二个对象是否是强制转换为false的类型,例如0NaNnull。 列出两个对象的键并将它们连接起来以测试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/

一个重要的观察,这会将数组转换为对象并比较相同索引位置的值。由于需要额外的复杂性,还有许多其他方法可以比较此函数未涵盖的数组。

编辑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;
}

测试:http://jsfiddle.net/gartz/Q3BtG/2/

答案 1 :(得分:6)

你可以使用创建MongoDB兼容(重命名/取消设置/设置)差异的rus-diff https://github.com/mirek/node-rus-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' } }

答案 2 :(得分:5)

回馈我对Gabriel Gartz版本的修改。这个工作在严格模式下并删除数组检查 - 将始终为false。它还从diff中删除空节点。

                //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;
                };

答案 3 :(得分:0)

假设我们要比较两个相同的对象,并减去如果对象字段计数匹配,则遵循下面的代码。

var obj1 = {
  "Agent": "12819",
  "Beneficiary": "476949",
  "BillingDetail": "13772",
  "BillingInvoice": "914548",
  "Claim": "1192",
  "Customer": "656320",
  "LifeAssured": "228493",
  "Payment": "1091661",
  "Policy/Proposal": "263196",
  "Product": "9",
  "ProductComponent": "53",
  "ProductComponentOption": "2239791",
  "ProductOption": "568785",
  "TransactionDetail": "4289240"
}

var obj2 = {
  "Agent": "1289",
  "Beneficiary": "47694",
  "BillingDetail": "13772",
  "BillingInvoice": "914548",
  "Claim": "1192",
  "Customer": "656320",
  "LifeAssured": "22893",
  "Payment": "1091661",
  "Policy/Proposal": "26316",
  "Product": "2",
  "ProductComponent": "52",
  "ProductComponentOption": "223971",
  "ProductOption": "56885",
  "TransactionDetail": "4289240"
}


function diff(obj1, obj2) {
const result = {};
for(var o1 in obj1){
	if(obj2[o1]){
		result[o1] = obj1[o1] - obj2[o1];
	}
}
return result;
}   

console.log(diff(obj1,obj2))

结果:

{
  "Agent": 11530,
  "Beneficiary": 429255,
  "BillingDetail": 0,
  "BillingInvoice": 0,
  "Claim": 0,
  "Customer": 0,
  "LifeAssured": 205600,
  "Payment": 0,
  "Policy/Proposal": 236880,
  "Product": 7,
  "ProductComponent": 1,
  "ProductComponentOption": 2015820,
  "ProductOption": 511900,
  "TransactionDetail": 0
}

答案 4 :(得分:0)

我们可以使用JSON.Stringify

var obj1 = {
  "Agent": "12819",
  "Beneficiary": "476949",
  "BillingDetail": "13772",
  "BillingInvoice": "914548",
  "Claim": "1192",
  "Customer": "656320",
  "LifeAssured": "228493",
  "Payment": "1091661",
  "Policy/Proposal": "263196",
  "Product": "9",
  "ProductComponent": "53",
  "ProductComponentOption": "2239791",
  "ProductOption": "568785",
  "TransactionDetail": "4289240"
}

var obj2 = {
  "Agent": "1289",
  "Beneficiary": "47694",
  "BillingDetail": "13772",
  "BillingInvoice": "914548",
  "Claim": "1192",
  "Customer": "656320",
  "LifeAssured": "22893",
  "Payment": "1091661",
  "Policy/Proposal": "26316",
  "Product": "2",
  "ProductComponent": "52",
  "ProductComponentOption": "223971",
  "ProductOption": "56885",
  "TransactionDetail": "4289240"
}

JSON.stringify(obj1) == JSON.stringify(obj2)
false

var obj3 = {
  "Agent": "1289",
  "Beneficiary": "47694",
  "BillingDetail": "13772",
  "BillingInvoice": "914548",
  "Claim": "1192",
  "Customer": "656320",
  "LifeAssured": "22893",
  "Payment": "1091661",
  "Policy/Proposal": "26316",
  "Product": "2",
  "ProductComponent": "52",
  "ProductComponentOption": "223971",
  "ProductOption": "56885",
  "TransactionDetail": "4289240"
}

JSON.stringify(obj2) == JSON.stringify(obj3)
true