首页 > 解决方案 > jq 根据外部映射替换值

问题描述

我想更改另一个 json 文件指定的 json 文件中的字段。我的输入文件是这样的:

{"id": 10, "name": "foo", "some_other_field": "value 1"}
{"id": 20, "name": "bar", "some_other_field": "value 2"}
{"id": 25, "name": "baz", "some_other_field": "value 10"}

我有一个外部覆盖文件,它指定name在某些对象中应该如何被覆盖,例如:

{"id": 20, "name": "Bar"}
{"id": 10, "name": "foo edited"}

如上所示,override 可能比 input 短,在这种情况下name应该保持不变。这两个文件都可以轻松放入可用内存中。

鉴于上述输入和覆盖,我想获得以下输出:

{"id": 10, "name": "foo edited", "some_other_field": "value 1"}
{"id": 20, "name": "Bar", "some_other_field": "value 2"}
{"id": 25, "name": "baz", "some_other_field": "value 10"}

作为一个初学者jq,我真的不知道从哪里开始。虽然有一些问题涵盖了类似的基础(最接近的是这个),但我无法弄清楚如何将解决方案应用于我的案例。

标签: jq

解决方案


有很多可能性,但可能最简单、有效的解决方案是使用内置函数:INDEX/2,例如如下:

jq -n --slurpfile dict f2.json '
  (INDEX($dict[]; .id) | map_values(.name)) as $d
  | inputs
  | .name = ($d[.id|tostring] // .name)
' f1.json

inputs与 -n 选项一起使用来读取第一个文件,以便可以依次处理每个 JSON 对象。

由于解决方案很短,借助在线jq 手册应该很容易弄清楚。

警告

该解决方案附带一个警告:由于使用“tostring”(例如,如果两者都发生),字典中的 id 之间没有“冲突{"id": 10}{"id": "10"}

如果字典确实或可能有这样的冲突,那么可以相应地调整上述解决方案,但这有点棘手。


推荐阅读