JSON 扁平化实战:把嵌套对象拍成点号键再还原回去
讲清楚 JSON 扁平化是什么:嵌套对象拍成 a.b.c 这样的点号键,数组下标怎么处理,怎么用在转 CSV、做 diff、写环境变量上,以及怎么干净还原回嵌套结构。
JSON 扁平化实战:把嵌套对象拍成点号键再还原回去
嵌套 JSON 读起来舒服,处理起来麻烦。一个三层深的对象,想丢进 .env 文件、想塞进表格、想跟另一份配置做 diff,都得先把那些大括号摊开。扁平化做的就是这件事:把每一层嵌套用一个分隔符拼成单层的键,层级关系全编码进键名本身。
扁平化到底在干什么
扁平化就是把多层嵌套压成一层。原来靠大括号表达的父子关系,改成靠键名里的分隔符表达。默认分隔符是点号,所以一个嵌套对象会变成 a.b.c 这样的键。
举个具体的:
输入
{
"db": { "host": "localhost", "port": 5432 },
"features": { "checkout": { "retryLimit": 3 } },
"tags": ["alpha", "beta"]
}
扁平化后
{
"db.host": "localhost",
"db.port": 5432,
"features.checkout.retryLimit": 3,
"tags.0": "alpha",
"tags.1": "beta"
}
注意三件事:db.host 把两层并成一个键;features.checkout.retryLimit 把三层并成一个键,藏在最里头的那个值现在一眼能看到;数组元素用下标当键段,tags.0、tags.1。还有一个容易被忽略的点,值的类型没动,5432 还是数字,3 还是数字,不会因为变成扁平结构就被转成字符串。
点号路径是怎么拼出来的
规则很朴素:从根走到每个叶子值,沿途经过的每个键按顺序用分隔符连起来,就是这个叶子的扁平键。features 进 checkout 进 retryLimit,连起来就是 features.checkout.retryLimit。这条路径其实就是这个值在原对象里的定位坐标,看到键名就知道它原来在哪一层。
这也是为什么扁平化对调试友好。我自己排查过一次预发环境的诡异故障,两份服务配置肉眼看一模一样,可有个请求就是挂。把两份都扁平化之后丢进 diff,真正改掉的那行直接以 features.checkout.retryLimit 一个键显出来,根本不用一层层展开大括号去对眼睛。那种藏在第三层的差异,扁平化能逼它现形。
数组下标:用 a.0 还是 a[0]
数组没有键,只有位置,所以扁平化用下标当键段。这里有两种写法,按下游工具来选:
- 数字键风格:
{"tags":["x","y"]}拍成{"tags.0":"x","tags.1":"y"}。在 .env 和配置工具里更常见。 - 方括号风格:同样的输入变成
{"tags[0]":"x","tags[1]":"y"}。当对象的键本身可能是纯数字时,方括号能消歧义,一眼看出这是数组下标而不是对象键。
两种风格各有适用面,选哪个不重要,重要的是还原时要用同一个设置。
几个真实用途
扁平化不是为了好看,是为了让 JSON 能进那些只认扁平键的地方。
写环境变量和键值库。Consul、etcd、.env 文件、AWS Parameter Store 都只认扁平键。把嵌套配置拍平,db.host 和 db.port 就成了能直接写进去的顶层键。分隔符选下划线的话,DB_HOST / DB_PORT 直接落进 env 文件,连改名都省了。
转表格和 CSV。想把一条嵌套记录变成表格里的一行,扁平化后每个叶子值正好对应一个列头:address.city、address.zip、tags.0、tags.1。原来用嵌套表达的结构,摊开就是普通的列。如果你要的是规整的逗号分隔输出,接着用 JSON 转 CSV 把这些列拼成表格文件更顺手。
做配置对比。前面那个 diff 的例子就是。扁平键让深层改动变成单行差异。
怎么干净地还原回嵌套
扁平化的反向操作叫 unflatten,把方向一切、扁平对象一粘就行。键会按分隔符拆开,一层层重建回嵌套:{"user.address.city":"北京"} 变回 {"user":{"address":{"city":"北京"}}}。如果某个键段是数字(或方括号风格下的方括号下标),它会重建成数组元素,所以 {"tags.0":"x","tags.1":"y"} 能还原成 {"tags":["x","y"]}。
想往返干净,只需记住两条。第一,选项必须一致,扁平和还原要用同一个分隔符、同一种数组风格,用 a[0] 拍却用 a.0 还原,数字段会被重建成对象键而不是数组,结构悄悄变了样。第二,分隔符别撞上键里本来就有的字符。如果键里含点,比如 file.name,再用点号扁平化,还原时就分不清这个点是字面量还是层级边界,这时候换成下划线或一个数据里绝不出现的自定义分隔符。
i18n 翻译树是个典型的往返场景:翻译文件按命名空间嵌套,多数翻译平台只要 home.title 这样的扁平键,拍平交给译员,回传后再还原成 i18n 库加载的嵌套结构,键名不用手动重搭。
校验或美化原始 JSON 可以先过一遍 JSON 格式化,再拿干净的结构来扁平化。要在浏览器里直接做嵌套与扁平的双向转换,用 JSON 扁平化 / 还原,分隔符、数组风格、类型保留都已经处理好,全程本地运行,什么都不上传。
Made by Toolora · Updated 2026-06-13