使用PowerShell转换含嵌套数组的JSON到CSV耗时过长问题排查
PowerShell处理嵌套JSON转CSV:解决性能慢与数据集中在单个单元格的问题
首先得说你当前代码的几个问题,这也是导致慢和格式异常的核心原因:
- 空数组展开的坑:你的代码里用了
Select * -Expand tagsOfEntities,但tagsOfEntities是空数组,这会让PowerShell把每个problem对象拆分成空条目,不仅打乱数据结构,还会增加大量不必要的处理量,直接拖慢运行速度。 - 连续Expand的逻辑错误:链式调用多次
Select -Expand会让数据扁平化的逻辑彻底混乱,尤其是当有多个嵌套结构时,这种方式无法正确把外层属性和嵌套数组的每个条目关联起来,最后输出的CSV自然会因为结构不对,所有数据挤在一个单元格里。 - 性能浪费:这种链式操作会反复遍历和转换对象,当JSON数据量较大时,性能损耗会被无限放大,导致运行时长长达2小时。
接下来给你一个更高效且能正确输出CSV的解决方案,核心思路是手动控制嵌套结构的扁平化,明确把外层属性和每个嵌套条目合并:
# 读取并解析JSON文件 $jsonContent = Get-Content C:\Documents\feed.json -Raw | ConvertFrom-Json # 逐层处理嵌套结构,生成扁平化的对象集合 $flattenedRecords = $jsonContent.result.problems | ForEach-Object { $currentProblem = $_ # 遍历ranked数组,将每个ranked项与外层problem属性合并 foreach ($rankedItem in $currentProblem.ranked) { [PSCustomObject]@{ # 外层problem的基础属性 id = $currentProblem.id displayName = $currentProblem.displayName impact = $currentProblem.impact status = $currentProblem.status tagsOfEntities = $currentProblem.tagsOfEntities -join ';' # 空数组转为空字符串,有内容则用分号分隔 RootCause = $currentProblem.RootCause # ranked数组的属性 entityId = $rankedItem.entityId entityName = $rankedItem.entityName severityLevel = $rankedItem.severityLevel # 嵌套对象affectedCounts的属性,重命名避免歧义 affected_INFRA = $currentProblem.affectedCounts.INFRA affected_STRUCTURE = $currentProblem.affectedCounts.STRUCTURE affected_APPLICATION= $currentProblem.affectedCounts.APPLICATION # 嵌套对象recoveredCounts的属性 recovered_INFRA = $currentProblem.recoveredCounts.INFRA recovered_STRUCTURE = $currentProblem.recoveredCounts.STRUCTURE recovered_APPLICATION = $currentProblem.recoveredCounts.APPLICATION } } } # 转换为CSV并输出,指定UTF8编码避免乱码 $flattenedRecords | ConvertTo-Csv -NoTypeInformation | Out-File C:\Documents\output.csv -Encoding UTF8
这个方案的优势:
- 性能更优:只遍历必要的层级,没有多余的Expand操作,大幅减少不必要的对象转换和遍历,运行速度会快很多。
- 格式正确:每个ranked条目都会和对应的problem属性组合成一行,CSV的每列对应一个属性,不会出现数据集中在单个单元格的情况。
- 灵活可控:你可以根据需求调整嵌套属性的处理方式,比如
tagsOfEntities如果有内容,用分号分隔成字符串,方便在CSV中查看;如果不需要某个属性,直接从PSCustomObject里删掉就行。
另外补充两个小建议:
- 如果你的JSON文件非常大,可以考虑用
Get-Content -ReadCount 1000分批读取解析,但对于大多数场景,上面的代码已经足够高效。 - 一定要加
-Encoding UTF8参数,避免Out-File默认编码导致的乱码问题。
内容的提问来源于stack exchange,提问作者asr
相关产品推荐
相关产品推荐

