如何合并JSON
2025/05/20
6分钟阅读

如何合并JSON

在不同编程语言中合并JSON对象的综合指南

JSON合并介绍

合并JSON对象是数据处理、配置管理和API交互中的一项基本操作。无论您是合并用户设置、合并配置文件,还是聚合API响应,正确理解如何合并JSON对象对现代开发至关重要。

JSON合并是指将两个或多个JSON对象合并成一个统一对象的过程。对于扁平对象来说,这个过程可能很简单,但在处理嵌套结构、数组和冲突值时会变得更加复杂。

基本JSON合并概念

在深入实现细节之前,了解一些与JSON合并相关的关键概念很重要:

浅合并与深合并

  • 浅合并:只合并顶层属性。当两个对象包含相同属性时,第二个对象的值会覆盖第一个对象的值。
  • 深合并:合并操作递归遍历对象树,合并嵌套对象而不是替换它们。

处理冲突值的合并策略

合并JSON对象时,可以通过几种方式处理冲突值:

策略描述使用场景
后者优先最后一个对象的值覆盖较早的值默认配置
先者优先保留第一个对象的值保留用户设置
自定义逻辑为不同属性应用特定逻辑复杂业务规则
冲突时报错检测到冲突时引发错误关键数据完整性

JavaScript合并JSON的方法

JavaScript提供了几种内置方法来合并JSON对象:

使用Object.assign()

Object.assign()方法执行浅合并,将源对象的所有可枚举自有属性复制到目标对象。

const json1 = { name: "John", age: 30 };
const json2 = { city: "New York", age: 31 };

const merged = Object.assign({}, json1, json2);
console.log(merged);
// 输出: { name: "John", city: "New York", age: 31 }

注意,具有相同键的属性会被参数列表中靠后的对象覆盖。

使用展开运算符 (...)

展开运算符提供了一种更简洁的方式来合并对象:

const json1 = { name: "John", age: 30 };
const json2 = { city: "New York", age: 31 };

const merged = { ...json1, ...json2 };
console.log(merged);
// 输出: { name: "John", city: "New York", age: 31 }

这种方法也会用后面对象的值覆盖重复的键。

深度合并JSON对象

Object.assign()和展开运算符都执行浅合并。对于嵌套对象,您需要一个深度合并实现:

递归深度合并函数

function deepMerge(target, source) {
  const output = Object.assign({}, target);
  
  if (isObject(target) && isObject(source)) {
    Object.keys(source).forEach(key => {
      if (isObject(source[key])) {
        if (!(key in target)) {
          Object.assign(output, { [key]: source[key] });
        } else {
          output[key] = deepMerge(target[key], source[key]);
        }
      } else {
        Object.assign(output, { [key]: source[key] });
      }
    });
  }
  
  return output;
}

function isObject(item) {
  return (item && typeof item === 'object' && !Array.isArray(item));
}

// 使用示例
const json1 = { 
  name: "John", 
  address: { 
    city: "New York", 
    zip: 10001 
  } 
};

const json2 = { 
  name: "Jane", 
  address: { 
    state: "NY" 
  } 
};

const merged = deepMerge(json1, json2);
console.log(merged);
// 输出: { 
//   name: "Jane", 
//   address: { 
//     city: "New York", 
//     zip: 10001, 
//     state: "NY" 
//   } 
// }

使用库合并JSON

对于更复杂的合并场景,考虑使用成熟的库:

Lodash的merge和mergeWith

Lodash提供了强大的深度合并函数:

const _ = require('lodash');

const json1 = { user: { name: "John", data: [1, 2] } };
const json2 = { user: { age: 30, data: [3, 4] } };

// 基本深度合并
const merged1 = _.merge({}, json1, json2);
console.log(merged1);
// 输出: { user: { name: "John", age: 30, data: [3, 4] } }

// 使用mergeWith自定义合并
const merged2 = _.mergeWith({}, json1, json2, (objValue, srcValue) => {
  if (Array.isArray(objValue)) {
    return objValue.concat(srcValue);
  }
});
console.log(merged2);
// 输出: { user: { name: "John", age: 30, data: [1, 2, 3, 4] } }

deepmerge包

deepmerge npm包专为深度合并而设计:

const deepmerge = require('deepmerge');

const json1 = { user: { name: "John", hobbies: ["reading"] } };
const json2 = { user: { age: 30, hobbies: ["swimming"] } };

// 默认合并(连接数组)
const merged = deepmerge(json1, json2);
console.log(merged);
// 输出: { user: { name: "John", age: 30, hobbies: ["reading", "swimming"] } }

// 自定义数组合并
const overwriteMerge = (destinationArray, sourceArray) => sourceArray;
const options = { arrayMerge: overwriteMerge };
const mergedCustom = deepmerge(json1, json2, options);
console.log(mergedCustom);
// 输出: { user: { name: "John", age: 30, hobbies: ["swimming"] } }

其他语言中的JSON合并

Python

使用内置的字典更新方法:

import json

json1_str = '{"name": "John", "age": 30}'
json2_str = '{"city": "New York", "age": 31}'

# 将JSON字符串解析为字典
json1 = json.loads(json1_str)
json2 = json.loads(json2_str)

# 合并字典
merged = {**json1, **json2}  # Python 3.5+

# 转换回JSON字符串
merged_json = json.dumps(merged)
print(merged_json)
# 输出: {"name": "John", "city": "New York", "age": 31}

Python中的深度合并:

def deep_merge(dict1, dict2):
    result = dict1.copy()
    for key, value in dict2.items():
        if key in result and isinstance(result[key], dict) and isinstance(value, dict):
            result[key] = deep_merge(result[key], value)
        else:
            result[key] = value
    return result

json1 = {"user": {"name": "John", "settings": {"theme": "dark"}}}
json2 = {"user": {"age": 30, "settings": {"notifications": True}}}

merged = deep_merge(json1, json2)
print(merged)
# 输出: {'user': {'name': 'John', 'settings': {'theme': 'dark', 'notifications': True}, 'age': 30}}

Ruby

使用Hash#merge方法:

require 'json'

json1_str = '{"name": "John", "age": 30}'
json2_str = '{"city": "New York", "age": 31}'

# 将JSON字符串解析为哈希
json1 = JSON.parse(json1_str)
json2 = JSON.parse(json2_str)

# 合并哈希
merged = json1.merge(json2)

# 转换回JSON字符串
merged_json = JSON.generate(merged)
puts merged_json
# 输出: {"name":"John","city":"New York","age":31}

Ruby中的深度合并:

require 'json'

# Ruby的内置deep_merge
require 'active_support/core_ext/hash/deep_merge'

json1 = JSON.parse('{"user": {"name": "John", "settings": {"theme": "dark"}}}')
json2 = JSON.parse('{"user": {"age": 30, "settings": {"notifications": true}}}')

merged = json1.deep_merge(json2)
puts JSON.generate(merged)
# 输出: {"user":{"name":"John","settings":{"theme":"dark","notifications":true},"age":30}}

特殊合并情况

合并数组

合并包含数组的JSON对象时,有几种策略:

  1. 替换:后面的数组完全替换前面的数组
  2. 连接:合并两个数组的元素
  3. 按索引合并:合并相同位置的数组元素
  4. 按ID合并:基于标识符字段合并数组元素
// 连接数组示例
const json1 = { tags: ["important", "urgent"] };
const json2 = { tags: ["completed", "archived"] };

const merged = {
  ...json1,
  tags: [...json1.tags, ...json2.tags]
};
console.log(merged);
// 输出: { tags: ["important", "urgent", "completed", "archived"] }

// 按ID合并数组示例
const users1 = { users: [{ id: 1, name: "John" }, { id: 2, name: "Jane" }] };
const users2 = { users: [{ id: 1, age: 30 }, { id: 3, name: "Bob", age: 25 }] };

function mergeArraysById(arr1, arr2, idKey) {
  const merged = [...arr1];
  
  arr2.forEach(item2 => {
    const item1Index = merged.findIndex(item1 => item1[idKey] === item2[idKey]);
    
    if (item1Index >= 0) {
      merged[item1Index] = { ...merged[item1Index], ...item2 };
    } else {
      merged.push(item2);
    }
  });
  
  return merged;
}

const mergedUsers = {
  users: mergeArraysById(users1.users, users2.users, 'id')
};

console.log(mergedUsers);
// 输出: {
//   users: [
//     { id: 1, name: "John", age: 30 },
//     { id: 2, name: "Jane" },
//     { id: 3, name: "Bob", age: 25 }
//   ]
// }

处理null和undefined值

合并对象时,您需要决定如何处理nullundefined值:

const json1 = { name: "John", age: null, city: undefined };
const json2 = { age: 30 };

// 默认行为(复制null值,忽略undefined)
const merged1 = Object.assign({}, json1, json2);
console.log(merged1);
// 输出: { name: "John", age: 30 }

// 深度合并中的自定义处理
function customDeepMerge(target, source) {
  const output = Object.assign({}, target);
  
  if (isObject(target) && isObject(source)) {
    Object.keys(source).forEach(key => {
      // 跳过源中的null值
      if (source[key] === null) return;
      
      if (isObject(source[key])) {
        if (!(key in target)) {
          output[key] = source[key];
        } else {
          output[key] = customDeepMerge(target[key], source[key]);
        }
      } else {
        output[key] = source[key];
      }
    });
  }
  
  return output;
}

用于合并JSON的命令行工具

使用jq

jq是一个功能强大的命令行JSON处理器,可以合并JSON文件:

# 合并两个JSON文件
jq -s '.[0] * .[1]' file1.json file2.json > merged.json

# 带有自定义数组处理的深度合并
jq -s '.[0] * .[1] | .array = (.[0].array + .[1].array)' file1.json file2.json > merged.json

使用Node.js

您可以创建一个简单的脚本来使用Node.js合并JSON文件:

const fs = require('fs');
const _ = require('lodash');

// 读取JSON文件
const file1 = JSON.parse(fs.readFileSync('file1.json', 'utf8'));
const file2 = JSON.parse(fs.readFileSync('file2.json', 'utf8'));

// 合并对象
const merged = _.merge({}, file1, file2);

// 写入结果
fs.writeFileSync('merged.json', JSON.stringify(merged, null, 2));

合并JSON的最佳实践

  1. 明确处理重复键:了解您选择的方法如何处理键冲突
  2. 考虑不可变性:创建新对象而不是修改现有对象
  3. 谨慎处理深度合并:对嵌套对象使用适当的递归方法或库
  4. 验证合并结果:确保最终对象具有有效的结构
  5. 使用边缘情况进行测试:空对象、null值、深度嵌套结构
  6. 记录您的合并策略:明确说明如何解决冲突
  7. 考虑性能:对于大型对象,一些深度合并实现可能效率低下

结论

合并JSON对象是一个常见但细致的操作。适当的合并策略取决于您的特定需求、数据结构和语言环境。通过理解各种合并技术及其含义,您可以有效地结合不同来源的数据,同时保持数据完整性并满足应用程序的需求。

作者

avatar for Corey
Corey

分类

新闻通讯

加入社区

订阅我们的新闻通讯,获取最新消息和更新