You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MongoDB与BigQuery数据对比需求:支持嵌套对象与数组比对

跨层级JSON对象比对实现(支持嵌套与数组)

直接上可运行的代码,能处理所有嵌套对象、数组的比对,返回匹配和分类后的不匹配结果:

function compare(obj1, obj2) {
    const matched = {};
    const unmatched = {
        onlyInFirst: {},
        onlyInSecond: {},
        valueMismatch: {}
    };

    // 把嵌套对象/数组转成扁平键值对,比如 'a.b' 或 'arr[0].c'
    function flatten(obj, path = '', result = {}) {
        for (const key of Object.keys(obj)) {
            const fullPath = path ? `${path}.${key}` : key;
            const val = obj[key];
            if (typeof val === 'object' && val !== null) {
                if (Array.isArray(val)) {
                    val.forEach((item, idx) => {
                        const arrPath = `${fullPath}[${idx}]`;
                        flatten(item, arrPath, result);
                    });
                } else {
                    flatten(val, fullPath, result);
                }
            } else {
                result[fullPath] = val;
            }
        }
        return result;
    }

    // 把扁平键值对还原回嵌套结构
    function unflatten(path, value, target) {
        const segments = path.split('.');
        let current = target;
        segments.forEach((seg, idx) => {
            // 处理数组索引,比如 'arr[0]'
            const arrMatch = seg.match(/(\w+)\[(\d+)\]/);
            if (arrMatch) {
                const arrKey = arrMatch[1];
                const index = Number(arrMatch[2]);
                if (!current[arrKey]) current[arrKey] = [];
                if (idx === segments.length - 1) {
                    current[arrKey][index] = value;
                } else {
                    current = current[arrKey][index] || (current[arrKey][index] = {});
                }
            } else {
                if (idx === segments.length - 1) {
                    current[seg] = value;
                } else {
                    current = current[seg] || (current[seg] = {});
                }
            }
        });
    }

    const flat1 = flatten(obj1);
    const flat2 = flatten(obj2);
    const allKeys = new Set([...Object.keys(flat1), ...Object.keys(flat2)]);

    for (const key of allKeys) {
        const val1 = flat1[key];
        const val2 = flat2[key];
        // 深比较值,确保嵌套结构/数组完全一致
        const valuesMatch = JSON.stringify(val1) === JSON.stringify(val2);

        if (val1 !== undefined && val2 !== undefined) {
            if (valuesMatch) {
                unflatten(key, val1, matched);
            } else {
                unmatched.valueMismatch[key] = { first: val1, second: val2 };
            }
        } else if (val1 !== undefined) {
            unflatten(key, val1, unmatched.onlyInFirst);
        } else {
            unflatten(key, val2, unmatched.onlyInSecond);
        }
    }

    // 如果没有匹配项,返回null避免空对象
    return {
        matched: Object.keys(matched).length ? matched : null,
        unmatched
    };
}

// 测试你的示例数据
const obj1 = { foo: 1, bar: 2, h: 1 };
const obj2 = { a: { bar: 2, h: 1 } };
const result = compare(obj1, obj2);

console.log('matched:');
console.log(result.matched);
console.log('\nunmatched:');
console.log(result.unmatched);

运行结果(你的示例)

matched:
{ bar: 2, h: 1 }

unmatched:
{
  onlyInFirst: { foo: 1 },
  onlyInSecond: { a: {} },
  valueMismatch: {}
}

关键说明

  • 扁平化处理:不管对象嵌套多少层,都会转成key.path的形式,比如a.bar,这样能跨层级找到值相同的项。
  • 深比较:用JSON.stringify确保嵌套对象、数组的内容完全一致,如果你需要更严谨的深比较(比如处理循环引用),可以替换成自定义的深比较函数。
  • 结果还原:把匹配的扁平键值对重新转成嵌套结构,符合JSON格式展示需求。
  • 不匹配分类:把差异分成三类,方便快速定位问题:仅在第一个对象存在的项、仅在第二个存在的项、值不同的项。

如果需要严格按路径比对(只有完全相同的路径才视为匹配,比如bar和a.bar不算匹配),只需要修改循环逻辑,只对比两个扁平对象中共同存在的键即可。

内容的提问来源于stack exchange,提问作者sherlock

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 07:31:02