扁平化嵌套JSON时如何保留键名以实现反向嵌套?
保留嵌套JSON扁平化后的父级键名,实现可还原的扁平化方案
我明白你现在的核心需求:既要把嵌套的JSON结构扁平化,又要保留完整的父级键路径,这样后续还能顺利还原回原始的嵌套格式。其实这个思路很清晰——在扁平化的过程中跟踪每一层的键名,用一个约定的分隔符(比如你示例里的#)把路径拼接起来就行。下面给你具体的实现方案:
问题回顾
你有一套特殊的嵌套JSON结构:每一层的键对应一个包含dataType、value、someKey的数组;当dataType为Object时,value里又是重复的嵌套结构。当前的扁平化操作丢失了父级键(比如firstLevelKey2、secondLevelKey2),你需要生成类似firstLevelKey2#secondLevelKey2#thirdLevelKey1这样的完整路径键名,保证可还原。
原始嵌套结构
[ { firstLevelKey1 : [{ dataType : 'String' },{ value : 'someString' },{ someKey : 'someValue' }] }, { firstLevelKey2:[{ dataType : 'Object' },{ value : [{ secondLevelKey1 :[{ dataType : 'String' },{ value : 'someString' },{ someKey : 'someValue' }] },{ secondLevelKey2 : [{ dataType : 'Object' },{ value : [{ thirdLevelKey1:[{ dataType : 'String' },{ value : 'someString' },{ someKey : 'someValue' }] },{ thirdLevelKey2 : [{ dataType : 'String' },{ value : 'someString' },{ someKey : 'someValue' }] },{ thirdLevelKey3 : [{ dataType : 'String' },{ value : 'someString' },{ someKey : 'someValue' }] }] },{ someKey : 'someValue' }] },{ secondLevelKey3 :[{ dataType : 'String' },{ value : 'someString' },{ someKey : 'someValue' }] }] },{ someKey : 'someValue' }] }, { firstLevelKey3 : [{ dataType : 'String' },{ value : 'someString' },{ someKey : 'someValue' }] } ]
实现思路与代码
核心逻辑是递归遍历+维护键路径:
- 遍历顶层数组的每个对象,提取根键作为初始路径
- 对每个键对应的数组,提取
dataType和value项 - 如果
dataType是String,直接把完整路径作为键,将数组加入结果 - 如果
dataType是Object,递归处理value里的嵌套对象,拼接父路径与当前键
JavaScript实现代码
function flattenWithPath(nestedArray) { const result = []; // 递归处理每一层对象,parentPath记录当前的父级键路径 function processItem(item, parentPath = '') { // 每个对象只有一个键,直接提取 const currentKey = Object.keys(item)[0]; const currentData = item[currentKey]; // 从数组中提取dataType、value、someKey对应的对象 const dataTypeObj = currentData.find(obj => obj.dataType); const valueObj = currentData.find(obj => obj.value); const someKeyObj = currentData.find(obj => obj.someKey); // 拼接当前完整路径 const fullPath = parentPath ? `${parentPath}#${currentKey}` : currentKey; if (dataTypeObj?.dataType === 'Object') { // 递归处理Object类型下的所有嵌套对象 valueObj.value.forEach(nestedItem => { processItem(nestedItem, fullPath); }); } else { // String类型直接加入结果数组 result.push({ [fullPath]: [dataTypeObj, valueObj, someKeyObj] }); } } // 遍历顶层数组的每个对象 nestedArray.forEach(item => processItem(item)); return result; } // 测试原始数据 const originalData = [/* 这里放入你原始的嵌套数据 */]; const flattenedResult = flattenWithPath(originalData); console.log(JSON.stringify(flattenedResult, null, 2));
运行结果(符合你的期望)
[ { "firstLevelKey1": [ { "dataType": "String" }, { "value": "someString" }, { "someKey": "someValue" } ] }, { "firstLevelKey2#secondLevelKey1": [ { "dataType": "String" }, { "value": "someString" }, { "someKey": "someValue" } ] }, { "firstLevelKey2#secondLevelKey2#thirdLevelKey1": [ { "dataType": "String" }, { "value": "someString" }, { "someKey": "someValue" } ] }, { "firstLevelKey2#secondLevelKey2#thirdLevelKey2": [ { "dataType": "String" }, { "value": "someString" }, { "someKey": "someValue" } ] }, { "firstLevelKey2#secondLevelKey2#thirdLevelKey3": [ { "dataType": "String" }, { "value": "someString" }, { "someKey": "someValue" } ] }, { "firstLevelKey2#secondLevelKey3": [ { "dataType": "String" }, { "value": "someString" }, { "someKey": "someValue" } ] }, { "firstLevelKey3": [ { "dataType": "String" }, { "value": "someString" }, { "someKey": "someValue" } ] } ]
额外:还原嵌套结构的思路
如果之后需要把扁平化的数据还原回原始嵌套格式,只需要按#拆分键路径,逐层构建嵌套对象即可:
function restoreFromFlattened(flattenedArray) { const result = []; flattenedArray.forEach(item => { const fullPath = Object.keys(item)[0]; const data = item[fullPath]; const pathParts = fullPath.split('#'); // 从最内层开始反向构建对象 let currentObj = { [pathParts.pop()]: data }; // 逐层向外嵌套,补充Object类型的结构 while (pathParts.length > 0) { const key = pathParts.pop(); currentObj = { [key]: [ { dataType: 'Object' }, { value: [currentObj] }, { someKey: data.find(obj => obj.someKey).someKey } ] }; } result.push(currentObj); }); return result; } // 测试还原 const restoredData = restoreFromFlattened(flattenedResult);
内容的提问来源于stack exchange,提问作者Manoj HT
相关产品推荐
相关产品推荐

