如何依据filterList泛化提取嵌套JSON Payload的指定字段?
通用实现方案:全量递归遍历提取指定字段
完全可以替代硬编码写路径的低效方式,核心逻辑是脱离对嵌套路径的依赖,对JSON结构做无预设的全量深度遍历,只要节点的键名匹配filterList,就直接把对应键值对提取到平铺结果中。
核心实现逻辑
- 优化匹配效率:把filterList数组转换为Set结构,将键名存在性判断的时间复杂度从O(n)降到O(1),避免长filterList带来的遍历性能损耗
- 实现递归遍历函数:函数需要适配所有JSON支持的结构类型,包括普通对象、数组,同时跳过null、基础类型等无法继续下钻的节点
- 遍历规则匹配:每走到一个键值对就做一次匹配判断,命中filterList就写入最终平铺结果;不管是否命中,只要当前值是可下钻的对象/数组结构,就继续递归深入遍历,直到走完整个JSON的所有节点
参考代码实现(以JavaScript为例)
function extractFields(payload, filterList) { const filterSet = new Set(filterList); const result = {}; function traverse(node) { // 跳过null、基础类型节点,避免无意义下钻 if (node === null || typeof node !== 'object') return; // 处理数组结构:遍历每个元素做递归 if (Array.isArray(node)) { node.forEach(item => traverse(item)); return; } // 处理普通对象结构 Object.entries(node).forEach(([key, value]) => { // 命中过滤列表就直接存入结果 if (filterSet.has(key)) { // 同名键处理可根据需求调整,此处默认后遍历到的值覆盖先匹配的值 result[key] = value; } // 可下钻的结构继续递归 if (typeof value === 'object' && value !== null) { traverse(value); } }); } traverse(payload); return result; }
调用示例
const testPayload = { student: { activities: { curriculum: { year: 2024, name: '计算机基础' } } }, school: { year: 2023 } } // 提取所有键名为year的字段 const extractResult = extractFields(testPayload, ['year']); // 最终输出:{ year: 2023 }
落地注意事项
- 同名键处理规则:如果不同嵌套层级存在相同的键名,需要提前明确处理逻辑——是后遍历到的覆盖先遍历到的值、保留第一次匹配到的值、还是把所有同键名的取值收集为数组返回,避免结果不符合业务预期
- 循环引用防护:如果待提取的payload存在自引用导致的循环嵌套,普通递归会触发栈溢出,这种场景可以加入弱引用集合记录已遍历过的节点,碰到重复节点直接跳过,避免无限递归
- 结构兼容:如果payload中包含Map、Set等非原生JSON结构,需要在遍历逻辑中单独适配,避免漏提取嵌套在这类结构中的目标字段
这套方案不需要提前掌握payload的具体层级结构,后续payload结构调整、嵌套层级加深时,完全不需要修改提取逻辑,对比硬编码路径的方式可以大幅降低维护成本。
内容的提问来源于stack exchange,提问作者Satyam Pisal
相关产品推荐
相关产品推荐

