
本文介绍一种高效、可复用的 JavaScript 方法,通过两层哈希映射(_id → itemId → 合并对象)实现嵌套数组的深度聚合,自动合并同 itemId 的字段,避免数据覆盖或丢失。
本文介绍一种高效、可复用的 javascript 方法,通过两层哈希映射(`_id` → `itemid` → 合并对象)实现嵌套数组的深度聚合,自动合并同 `itemid` 的字段,避免数据覆盖或丢失。
在处理业务数据(如库存、订单明细)时,常遇到结构类似如下 JSON 的嵌套数组:同一 _id(如仓库编号、单据号)下存在多个对象,每个对象又包含 items 数组,而不同来源的 items 中可能包含相同 itemId 但字段不同的记录(例如部分含 stockIn/stockOut,另一部分含 noFreeQtyCount/freeQtyCount)。目标是将相同 _id 下所有 items 按 itemId 合并为一个对象,保留所有字段(非覆盖,而是叠加),最终输出扁平化、去重且字段互补的嵌套结构。
核心思路是构建两级索引对象:
- 第一层以
_id为键,存储该 ID 下所有子项的聚合容器; - 第二层以
itemId为键,在每个_id容器内进一步归集对应商品项; - 使用
Object.assign()实现浅合并——当同一itemId出现多次时,后出现的属性会补全前次缺失字段,不会覆盖已有值(如itemId: "9"同时拥有stockIn和noFreeQtyCount,二者共存)。
以下是完整可运行的解决方案:
function groupByItemId(data) {
const mergedData = {}; // {_id: {itemId: {...merged}}}
data.forEach(entry => {
const _id = entry._id;
const items = entry.items || [];
if (!mergedData[_id]) {
mergedData[_id] = {};
}
items.forEach(item => {
const itemId = item.itemId;
if (!mergedData[_id][itemId]) {
mergedData[_id][itemId] = {};
}
Object.assign(mergedData[_id][itemId], item); // 浅合并:新增字段不丢失,同名字段后写入者覆盖
});
});
return Object.keys(mergedData).map(_id => ({
_id,
items: Object.values(mergedData[_id])
}));
}
// 示例输入
const inputData = [
{
"_id": "013",
"items": [
{"itemId": "4", "stockIn": 50, "stockOut": 0},
{"itemId": "9", "stockIn": 100, "stockOut": 0}
]
},
{
"_id": "013",
"items": [
{"itemId": "3", "noFreeQtyCount": 20, "freeQtyCount": 0},
{"itemId": "9", "noFreeQtyCount": 30, "freeQtyCount": 0}
]
}
];
console.log(groupByItemId(inputData));
// 输出:
// [
// {
// "_id": "013",
// "items": [
// {"itemId": "4", "stockIn": 50, "stockOut": 0},
// {"itemId": "9", "stockIn": 100, "stockOut": 0, "noFreeQtyCount": 30, "freeQtyCount": 0},
// {"itemId": "3", "noFreeQtyCount": 20, "freeQtyCount": 0}
// ]
// }
// ]
✅ 关键优势说明:
- ✅ 字段无损合并:
Object.assign()确保itemId: "9"的两次数据自动融合为一个对象,兼具stockIn与noFreeQtyCount字段; - ✅ 天然去重:
itemId作为二级键,重复项自动归一; - ✅ 支持任意字段组合:不限定字段名,适配动态业务模型;
- ✅ 时间复杂度优:O(n×m),其中 n 为外层数量、m 为平均
items长度,优于嵌套循环查找。
⚠️ 注意事项:
- 若存在同
itemId下相同字段但值冲突(如两次都定义了stockIn: 50和stockIn: 80),后者将覆盖前者——此时需根据业务逻辑改用自定义合并策略(如求和、取最大值等); - 所有
items数组必须存在且为数组类型,建议增加Array.isArray(items)校验提升健壮性; - 如需保持
items原始顺序(如按首次出现排序),可在最后对Object.values(...)结果按itemId插入顺序做稳定排序(需额外缓存顺序索引)。
该方法简洁、可靠,适用于库存汇总、多源数据对账、报表聚合等典型场景,是处理嵌套分组问题的工业级实践方案。










