Javascript 获取两个 json 对象的差异

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/8431651/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-24 05:59:20  来源:igfitidea点击:

Getting a diff of two json-objects

javascriptjqueryjsondiff

提问by Soroush Hakami

Scenario: I want a function that compares two JSON-objects, and returns a JSON-object with a list of the differences and if possible more data such as coverage metrics.

场景:我想要一个函数来比较两个 JSON 对象,并返回一个带有差异列表的 JSON 对象,如果可能的话,还有更多数据,例如覆盖率指标。

var madrid = '{"type":"team","description":"Good","trophies":[{"ucl":"10"}, {"copa":"5"}]}';
var barca = '{"type":"team","description":"Bad","trophies":[{"ucl":"3"}]}';

If i ran compare(madrid, barca)the returned object could look something like:

如果我运行compare(madrid, barca)返回的对象可能看起来像:

{"description" : "Bad", "trophies":[{"ucl":"3"}, {"copa":"5"}]}; 

Or something similar, you get the idea.

或者类似的东西,你明白了。

Does anyone know of a solution to this? I've already found one plugin, but I'd like to know if there are any alternatives.

有谁知道解决这个问题的方法?我已经找到了一个插件,但我想知道是否还有其他选择。

回答by Gabriel Gartz

It's possible to use a recursive function that iterates by the object keys. Then use the Object.isto test for NaNand null. Then test if the second object is the type that cast to falselike 0, NaN, or null. List the keys of both objects and concatenate them to test of missing keys in the obj1and then iterate it.

可以使用通过对象键进行迭代的递归函数。然后使用Object.is来测试NaNnull。然后测试如果第二对象是流延到该类型false喜欢0NaNnull。列出两个对象的键并将它们连接起来以测试 中缺少的键obj1,然后对其进行迭代。

When there is a difference between the same key values, it stores the value of object2and proceeds. If both key values are object means that can be recursively compared and so it does.

当相同的键值之间存在差异时,它会存储 的值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;
}

The code above is BSD licensed and can be used anywhere.

上面的代码是 BSD 许可的,可以在任何地方使用。

Test link: https://jsfiddle.net/gartz/vy9zaof2/54/

测试链接:https: //jsfiddle.net/gartz/vy9zaof2/54/

An important observation, this will convert arrays to objects and compare the values in the same index position. There are many other ways to compare arrays not covered by this function due to the required extra complexity.

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

EDIT 2/15/2019: This answer was changed to add the new ES2017 syntax and fix use-cases from comments.

编辑 2/15/2019:此答案已更改以添加新的 ES2017 语法并修复注释中的用例。



This is just a kickoff, I haven't tested it, but I began with a filter or comparator function, that is recursive, change it however you need to get priority results.

这只是一个开始,我还没有测试过,但我从一个过滤器或比较器函数开始,这是递归的,改变它但是你需要得到优先结果。

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

Tests: http://jsfiddle.net/gartz/Q3BtG/2/

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

回答by Mirek Rusin

You can use rus-diff https://github.com/mirek/node-rus-diffwhich creates MongoDB compatible (rename/unset/set) diff:

您可以使用 rus-diff https://github.com/mirek/node-rus-diff创建与 MongoDB 兼容的(重命名/取消设置/设置)差异:

// 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))

Outputs:

输出:

{ '$unset': { 'trophies.1': true },
  '$set': { description: 'Bad', 'trophies.0.ucl': '3' } }

回答by Leblanc Meneses

contributing back my changes to Gabriel Gartz version. This one works in strict mode and removes the array check - will always be false. It also removes empty nodes from the diff.

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

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

回答by KARTHIKEYAN.A

Suppose we want to compare two same objects and subtract if object field count match then follow the bellow code.

假设我们要比较两个相同的对象并在对象字段计数匹配时减去,然后按照以下代码进行操作。

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))

Result:

结果:

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