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

Json 使用jq合并具有公共id的密钥,json,key,jq,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”: [

考虑一个文件“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
的几种可能性之一。如果您的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的内容

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

INDEX/2
直接从builtin.jq:

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

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

索引/2的推广 调用 主要的
给你,但没有什么新东西。“baz”不应该被改变这个问题已经存在。你的问题是关于通用JSON操作的,如果你愿意,我可以为你提供一个替代的(非jq)简单解决方案。@Dmitry非常感谢你,但我只有基本的工具(grep、sed、sh和jq)在目标机器上,无法安装额外的软件包,我坚持使用JQT非常感谢,这非常有效。我需要一段时间才能真正理解这里发生了什么。
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)