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);
代码说明
- 顶层数组处理:用
Map存储arr1对象的_id与对应对象,实现O(1)时间复杂度的存在性判断,避免重复遍历数组。 - 嵌套locations处理:对已存在的顶层对象,同样用
Map管理其locations数组的_id,只添加arr2中未出现的location项。 - 数据纯净性:使用扩展运算符
...拷贝对象和数组,避免修改原数组的引用,保证原始数据不被污染。
该方法完美解决了顶层对象与嵌套对象的重复问题,完全符合期望输出要求。
内容的提问来源于stack exchange,提问作者Kanishk Patil
相关产品推荐
相关产品推荐

