使用jq合并具有公共ID的密钥

时间:2020-02-14 14:32:00

标签: json key jq

考虑文件“ b.json”:

[
  {
    "id": 3,
    "foo": "cannot be replaced, id isn't in a.json, stay untouched",
    "baz": "do not touch3"
  },
  {
    "id": 2,
    "foo": "should be replaced with 'foo new2'",
    "baz": "do not touch2"
  }
]

和'a.json':

[
  {
    "id": 2,
    "foo": "foo new2",
    "baz": "don't care"
  }
]

我想使用jq和来自a.json的匹配值来更新b.json中的键“ foo”。它也应该与a.json中的多个条目一起使用。

因此所需的输出是:

[
  {
    "id": 3,
    "foo": "cannot be replaced, id isn't in a.json, stay untouched",
    "baz": "do not touch3"
  },
  {
    "id": 2,
    "foo": "foo new2",
    "baz": "do not touch2"
  }
]

2 个答案:

答案 0 :(得分:1)

这是使用INDEX/2的几种可能性之一。如果您的jq没有内置此功能,请参见下文。

jq --argfile a a.json '
  INDEX($a[]; .id) as $dict
  | map( (.id|tostring) as $id
         | if ($dict|has($id)) then .foo = $dict[$id].foo 
           else . end)' b.json

还有其他方法可以传递a.json和b.json的内容。

注意事项

上面对INDEX的使用假定不存在“冲突”,例如,如果一个对象的.id等于1,而另一个对象的.id等于“ 1”,则会发生这种情况。如果可能发生这种冲突,则可以使用更复杂的INDEX定义。

INDEX/2

直接从Builtin.jq:

def INDEX(stream; idx_expr):
  reduce stream as $row ({}; .[$row|idx_expr|tostring] = $row);

答案 1 :(得分:1)

这是一个通用答案,除了它们是不同的JSON值之外,没有对.id密钥的值进行任何假设。

INDEX / 2的概括

def type2: [type, if type == "string" then . else tojson end];

def dictionary(stream; f):
  reduce stream as $s ({}; setpath($s|f|type2; $s));

def lookup(value):
  getpath(value|type2);

def indictionary(value):
  (value|type2) as $t
  | has($t[0]) and (.[$t[0]] | has($t[1]));

调用

jq --argfile a a.json -f program.jq b.json 

主要

dictionary($a[]; .id) as $dict
| b
| map( .id as $id 
       | if ($dict|indictionary($id)) 
         then .foo = ($dict|lookup($id).foo) 
         else . end)