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

JavaScript中对比合并对象数组:添加首个数组不存在的对象及嵌套对象

合并两个对象数组并去重(基于_id字段,含嵌套对象)

需求:对比两个JavaScript对象数组,将第二个数组中第一个数组不存在的对象(包括嵌套的Location对象)添加到第一个数组中,使用_id字段进行匹配校验。

此前尝试:

  • 使用filter方法,仅能移除不匹配元素,无法实现添加新元素的需求
  • 使用mergeDeep函数合并,但会出现嵌套对象重复的问题,无法过滤重复项

示例输入数组

let obj1 = [
    {
      "_id": "63eb2c20fd30492730e203bb",
      "name": "name 01",
      "isActive": true,
      "locations": [],
      "code": "888888"
    },
    {
      "_id": "638482b90b6d64eccee23be7",
      "name": "name 02",
      "isActive": true,
      "locations": [
        {
          "primaryContact": {
            "name": "name 03",
            "designation": "",
            "email": "",
            "phone": "+1 845566 556",
            "isBilling": true
          },
          "_id": "638484359f153cecd64212a8"
        },
        {
          "primaryContact": {
            "name": "name 04",
            "designation": "",
            "email": "",
            "phone": "(000) 000-0000",
            "isBilling": true
          },
          "_id": "638484359f153cecd6464789"
        },
        {
          "primaryContact": {
            "name": "name 05",
            "designation": "",
            "email": "",
            "phone": "(000) 000-0000",
            "isBilling": true
          },
          "_id": "638484359f153cecd65843a8"
        }
      ]
    }
  ]

let obj2=[
    {
      "_id": "63eb2c20fd30492730e203bb",
      "name": "name 01",
      "isActive": true,
      "locations": [],
      "code": "888888"
    },
    {
      "_id": "638482b90b6d64eccee23be7",
      "name": "name 02",
      "isActive": true,
      "locations": [
        {
          "primaryContact": {
            "name": "name 03",
            "designation": "",
            "email": "",
            "phone": "+1 845566 556",
            "isBilling": true
          },
          "_id": "638484359f153cecd64212a8"
        },
        {
          "primaryContact": {
            "name": "name 08",
            "designation": "",
            "email": "",
            "phone": "(000) 000-0000",
            "isBilling": true
          },
          "_id": "638484359f153ferg52a8"
        }
      ]
    },
    {
      "_id": "63eb2c20hijkl920e203bb",
      "name": "name 10",
      "isActive": true,
      "locations": [],
      "code": "888888"
    }
  ]

此前尝试的代码

function mergeDeep(target, source) {
  const isObject = (obj) => obj && typeof obj === 'object';

  if (!isObject(target) || !isObject(source)) {
    return source;
  }
  Object.keys(source).forEach(key => {
    const targetValue = target[key];
    const sourceValue = source[key];

    if (Array.isArray(targetValue) && Array.isArray(sourceValue)) {
      target[key] = targetValue.concat(sourceValue);
    } else if (isObject(targetValue) && isObject(sourceValue)) {
      target[key] = mergeDeep(Object.assign({}, targetValue), sourceValue);
    } else {
      target[key] = sourceValue;
    }
  });
  return target;
}

期望输出

let output = [
    {
      "_id": "63eb2c20fd30492730e203bb",
      "name": "name 01",
      "isActive": true,
      "locations": [],
      "code": "888888"
    },
    {
      "_id": "638482b90b6d64eccee23be7",
      "name": "name 02",
      "isActive": true,
      "locations": [
        {
          "primaryContact": {
            "name": "name 03",
            "designation": "",
            "email": "",
            "phone": "+1 845566 556",
            "isBilling": true
          },
          "_id": "638484359f153cecd64212a8"
        },
        {
          "primaryContact": {
            "name": "name 04",
            "designation": "",
            "email": "",
            "phone": "(000) 000-0000",
            "isBilling": true
          },
          "_id": "638484359f153cecd6464789"
        },
        {
          "primaryContact": {
            "name": "name 05",
            "designation": "",
            "email": "",
            "phone": "(000) 000-0000",
            "isBilling": true
          },
          "_id": "638484359f153cecd65843a8"
        },
        {
          "primaryContact": {
            "name": "name 08",
            "designation": "",
            "email": "",
            "phone": "(000) 000-0000",
            "isBilling": true
          },
          "_id": "638484359f153ferg52a8"
        }
      ]
    },
    {
      "_id": "63eb2c20hijkl920e203bb",
      "name": "name 10",
      "isActive": true,
      "locations": [],
      "code": "888888"
    }
  ];

解决方案

要实现需求,需要分两层处理:顶层对象数组的合并去重,以及每个对象内部locations数组的合并去重,核心都是基于_id判断是否已存在。

实现代码

function mergeArraysWithId(arr1, arr2) {
  // 创建顶层对象的id映射,快速查找是否存在
  const idMap = new Map();
  
  // 初始化映射,存入arr1的对象并保留原locations
  arr1.forEach(item => {
    const processedItem = {
      ...item,
      locations: [...item.locations]
    };
    idMap.set(item._id, processedItem);
  });
  
  // 遍历arr2,处理合并逻辑
  arr2.forEach(item => {
    if (idMap.has(item._id)) {
      // 顶层对象已存在,合并locations数组
      const existingItem = idMap.get(item._id);
      const locationIdMap = new Map();
      // 建立现有locations的id映射
      existingItem.locations.forEach(loc => locationIdMap.set(loc._id, loc));
      // 添加arr2中不存在的location项
      item.locations.forEach(loc => {
        if (!locationIdMap.has(loc._id)) {
          existingItem.locations.push({...loc});
        }
      });
    } else {
      // 顶层对象不存在,直接加入映射
      idMap.set(item._id, {...item});
    }
  });
  
  // 将映射转换为数组返回
  return Array.from(idMap.values());
}

// 使用示例
const mergedResult = mergeArraysWithId(obj1, obj2);
console.log(mergedResult);

代码说明

  1. 顶层数组处理:用Map存储arr1对象的_id与对应对象,实现O(1)时间复杂度的存在性判断,避免重复遍历数组。
  2. 嵌套locations处理:对已存在的顶层对象,同样用Map管理其locations数组的_id,只添加arr2中未出现的location项。
  3. 数据纯净性:使用扩展运算符...拷贝对象和数组,避免修改原数组的引用,保证原始数据不被污染。

该方法完美解决了顶层对象与嵌套对象的重复问题,完全符合期望输出要求。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 16:03:08