ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

用 jq --slurpfile 按共享 ID 将两个 JSON 文件拉链合并成一份

用 jq --slurpfile 按共享 ID 将两个 JSON 文件拉链合并成一份 文档教程知识库【免费下载链接】til:memo: Today I Learned项目地址https://gitcode.com/gh_mirrors/ti/til点击查看免费下载本文讲解如何在 TIL 开源仓库所收录的 jq 实战笔记基础上用一条jq单行命令把两份共享同一标识如slug的 JSON 文件拉链式合并成一份完整数据文件一提供主体记录文件二补充关联字段最终按共享 ID 拼接输出。读完本文你将掌握--slurpfile的参数语义、select过滤与对象并集运算符的组合用法并能直接把它复用到书籍元数据、配置合并、接口联表等真实场景。场景两份 JSON 文件一个共享标识假设我们有两份 JSON 文件。list1.json是一个对象数组记录了一些书籍的基础元数据比如slug唯一标识和title[ { slug: the-subtle-knife, title: The Subtle Knife }, { slug: all-systems-red, title: All Systems Red }, { slug: piranesi-abc123, title: Piranesi } ]list2.json的格式与之类似但每个对象携带的是另一块与slug绑定的补充元数据例如作者信息[ { slug: the-subtle-knife, author: Philip Pullman }, { slug: all-systems-red, author: Martha Wells }, { slug: piranesi-abc123, author: Susanna Clarke } ]目标很明确以slug为连接键把第二份文件里的字段合并进第一份文件形成一条条完整的记录。这个需求本质上是数据联表join。如果数据量不大与其手工复制粘贴大量字段或者为一个临时任务专门写一个完整脚本不如直接用jq的一条命令搞定——核心工具就是--slurpfile参数见 jq/zip-two-json-files-together-based-on-shared-id.md。一条命令完成拉链合并原文档给出的方案是一个jq单行命令同时传入两个文件名并通过--slurpfile把它们各自读入一个命名变量jq --slurpfile list1 list1.json --slurpfile list2 list2.json -n $list1[] as $item1 | $list2[] as $item2 | select($item1.slug $item2.slug) | $item1 $item2 运行后输出大致如下每条记录同时带上了标题和作者[ { slug: the-subtle-knife, title: The Subtle Knife, author: Philip Pullman }, { slug: all-systems-red, title: All Systems Red, author: Martha Wells }, { slug: piranesi-abc123, title: Piranesi, author: Susanna Clarke } ]为便于阅读示例中 JSON 字符串使用单引号简化书写实际 JSON 文件中请按标准使用双引号。拆解命令的每一部分这条命令虽然短但每个环节都值得逐行理解方便举一反三。--slurpfile把整个文件读成数组并绑定到命名变量--slurpfile list1 list1.json的意思是读取list1.json的全部内容slurp 的含义就是一次性吞下整个输入把它解析成一个 JSON 数组并绑定到变量名list1。命令中出现了两次--slurpfile list1 list1.json --slurpfile list2 list2.json于是过滤器内部可以直接用$list1、$list2引用这两个数组。这与 TIL 仓库中另一篇笔记 jq/turn-a-list-from-a-command-into-json.md 讲到的-s / --slurp是同一族概念--slurp把标准输入的整个内容读成数组而--slurpfile更进一步把指定文件的内容读成数组并赋给命名变量。因为这里有两个来源命名变量是唯一能区分它们的方式。-n不读取标准输入只执行过滤器-n是--null-input的缩写。加上它之后jq不会去读标准输入或额外的输入文件而是直接把null当作输入、执行一次过滤器。这样整个过滤器完全依赖$list1、$list2两个变量不会有无关输入干扰结果。$list1[] as $item1遍历数组中的每个元素$list1[]会把数组中的每个元素依次作为输出流的一个值as $item1则把当前元素绑定到变量$item1。配合管道$list1[] as $item1 | $list2[] as $item2实际上构成了一个嵌套循环外层遍历list1的每个对象内层遍历list2的每个对象从而产生两份数据的全部两两组合笛卡尔积。select(...)只保留匹配的组合select($item1.slug $item2.slug)是一个过滤条件只有当内层循环里的$item2与当前$item1的slug相等时该组合才会继续流向下一步。这一步把笛卡尔积压缩成了真正匹配上的配对等价于关系数据库中的 join 谓词。select是 jq 中最常用的过滤手段之一仓库中的 jq/find-all-objects-with-a-matching-key-value-pair.md 展示了它在数组映射场景中的更多用法例如配合map找出所有status reading的书籍可以作为进阶参考。$item1 $item2对象并集union这是合并真正发生的地方。在 jq 中作用于两个对象时执行的是字段并集两个对象的全部字段都会保留若存在同名字段右侧对象$item2的取值覆盖左侧$item1。于是$item1的slug、title与$item2的slug、author合并成一个新对象。这里slug在两份数据中取值相同覆盖后值不变可以放心让并集自然处理但如果两份数据在同一字段上存在差异就必须注意右操作数的优先级。管道|的语义jq 的|与 shell 管道类似但处理对象是数据流上一步产出的每个值都会作为下一步的输入被依次处理。四个步骤串联起来等价于遍历所有 (item1, item2) 组合 → 筛选出 slug 相等的组合 → 输出合并后的对象输出会逐条打到标准输出多条输出之间用换行分隔整体看起来就是拉链合并后的记录列表。实操复现从零跑通并落盘下面给出可以直接复制运行的完整示例。首先创建两份标准 JSON 文件cat list1.json EOF [ { slug: the-subtle-knife, title: The Subtle Knife }, { slug: all-systems-red, title: All Systems Red }, { slug: piranesi-abc123, title: Piranesi } ] EOF cat list2.json EOF [ { slug: the-subtle-knife, author: Philip Pullman }, { slug: all-systems-red, author: Martha Wells }, { slug: piranesi-abc123, author: Susanna Clarke } ] EOF然后运行合并命令。默认情况下结果输出到标准输出可以直接查看jq --slurpfile list1 list1.json --slurpfile list2 list2.json -n $list1[] as $item1 | $list2[] as $item2 | select($item1.slug $item2.slug) | $item1 $item2 如果想保存成新的 JSON 文件把标准输出重定向即可原文件保持不变jq --slurpfile list1 list1.json --slurpfile list2 list2.json -n $list1[] as $item1 | $list2[] as $item2 | select($item1.slug $item2.slug) | $item1 $item2 merged.json之后可以用jq顺手验证合并结果比如统计条数参考 jq/count-the-number-of-things-in-a-json-file.md 的length用法jq length merged.json边界情况与进阶思路在实际数据上应用这个模式前有几个行为值得提前了解无匹配的组合会被静默丢弃select直接过滤掉slug不相等的组合因此孤儿记录只在其中一份文件中出现的slug不会出现在输出里。如果希望保留未匹配记录并填充空值需要改用其他结构如以list1为基准遍历再在list2中查找。重复的slug会产生多条输出由于实现是两两组合 条件过滤任何一边出现重复slug时匹配到的每一对组合都会各输出一行。合并前最好先确认slug在各自文件中是唯一的。字段冲突时右操作数获胜$item1 $item2中同名键以$item2为准。若想让list1的字段优先把加法顺序调成$item2 $item1即可。大文件注意复杂度上述写法本质是嵌套循环两两比较的代价约为 O(n × m)。若两份数据规模都很大jq手册中还提供了面向哈希查找的INDEX/JOIN等内置函数适合作为进阶替代方案。相关参考本主题位于 TIL 仓库的 jq 分类下关联文档为 jq/zip-two-json-files-together-based-on-shared-id.md。同分类下的这些笔记可与本文互相印证jq/turn-a-list-from-a-command-into-json.md讲解-s / --slurp读入整个输入与--slurpfile同源jq/find-all-objects-with-a-matching-key-value-pair.mdselect过滤条件的更多实战组合jq/combine-an-array-of-objects-into-a-single-object.mdadd把对象数组合并成单个对象可作为合并结果再加工的手段jq/count-the-number-of-things-in-a-json-file.md用length验证合并后的记录数量。赞分享文档教程知识库【免费下载链接】til:memo: Today I Learned项目地址https://gitcode.com/gh_mirrors/ti/til点击查看免费下载相关推荐如何用 jq -n 配合 input 和 inputs 读取并聚合多个 JSON 输入如何用 jq n 配合 input 和 inputs 读取并聚合多个 JSON 输入 当你有多个 JSON 值来自管道、标准输入或命令行上指定的多个文件需CLI数据分析Rerun C 多进程共享录制实战用 RecordingId 将多次进程运行合并到同一份录制Rerun C 多进程共享录制实战用 RecordingId 将多次进程运行合并到同一份录制 导读 本文讲解 Rerun C SDK 中 Record数据可视化3D渲染数据分析jsPDF终极文档合并指南5个高效技巧将多个PDF文件合并为一个jsPDF终极文档合并指南5个高效技巧将多个PDF文件合并为一个 想要轻松实现PDF文档合并jsPDF作为强大的JavaScript PDF生成库提供了多后端创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表