Use jq to merge keys with common id

独自空忆成欢 提交于 2021-01-28 11:45:46

问题


consider a file '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"
  }
]

and 'a.json':

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

I want to update the key "foo" in b.json using jq with the matching value from a.json. It should also work with more than one entry in a.json.

Thus the desired output is:

[
  {
    "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"
  }
]

回答1:


Here's one of several possibilities that use INDEX/2. If your jq does not have this as a built-in, see below.

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

There are other ways to pass in the contents of a.json and b.json.

Caveat

The above use of INDEX assumes there are no "collisions", which would happen if, for example, one of the objects has .id equal to 1 and another has .id equal to "1". If there is a possibility of such a collision, then a more complex definition of INDEX could be used.

INDEX/2

Straight from builtin.jq:

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



回答2:


Here's a generic answer that makes no assumptions about the values of the .id keys except that they are distinct JSON values.

Generalization of 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]));

Invocation

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

main

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


来源:https://stackoverflow.com/questions/60228327/use-jq-to-merge-keys-with-common-id

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!