如何使用JQ合并两个JSON对象?(how to merge two JSON objects us

2019-09-28 03:13发布

我有两个文件JSON。 我想两个数组SomeFile2.json的追加到SomeFile1.json如下。

SomeFile1.json

[
  {
    "DNSName": "CLB-test-112a877451.ap-northeast-1.elb.amazonaws.com",
    "Instances": [
      {
        "InstanceId": "i-0886ed703de64028a"
      }
    ]
  },
  {
    "DNSName": "CLB-test1-156925981.ap-northeast-1.elb.amazonaws.com",
    "Instances": [
      {
        "InstanceId": "i-0561634c4g3b4fa25"
      }
    ]
  }
]

SomeFile2.json

[
  {
    "InstanceId": "i-0886ed703de64028a",
    "State": "InService"
  },
  {
    "InstanceId": "i-0561634c4g3b4fa25",
    "State": "InService"
  }
]

我想下面的结果:

[
  {
    "DNSName": "CLB-test-112a877451.ap-northeast-1.elb.amazonaws.com",
    "Instances": [
      {
        "InstanceId": "i-0886ed703de64028a"
        "State": "InService"
      }
    ]
  },
  {
    "DNSName": "CLB-test1-156925981.ap-northeast-1.elb.amazonaws.com",
    "Instances": [
      {
        "InstanceId": "i-0561634c4g3b4fa25"
        "State": "InService"
      }
    ]
  }
]

我在bash shell中通过处理jq 。 但是,未果。

Answer 1:

因为我发现JQ相当困难,我开始在一个程序的方法:使用Ruby的JSON模块:

ruby -rjson -e '
  states = JSON.parse(File.read(ARGV.shift)).map {|o| [o["InstanceId"], o["State"]]}.to_h
  data = JSON.parse(File.read(ARGV.shift))
  data.each do |obj|
    obj["Instances"].each do |instance|
      instance["State"] = states[instance["InstanceId"]] || "unknown"
    end
  end
  puts JSON.pretty_generate data
' SomeFile2.json SomeFile1.json 

但是,我们希望JQ,所以一些试验和错误,并在手册中找到此之后: https://stedolan.github.io/jq/manual/#Complexassignments - (注意,我改变了状态的实例之一,所以我可以验证输出更好)

$ cat SomeFile2.json 
[
  {
    "InstanceId": "i-0886ed703de64028a",
    "State": "InService"
  },
  {
    "InstanceId": "i-0561634c4g3b4fa25",
    "State": "NOTInService"
  }
]

首先,提取状态到对象映射ID的状态:

$ state_map=$( jq -c 'map({"key":.InstanceId, "value":.State}) | from_entries' SomeFile2.json )
$ echo "$state_map"
{"i-0886ed703de64028a":"InService","i-0561634c4g3b4fa25":"NOTInService"}

然后,更新的第一个文件的实例:

jq --argjson states "$state_map" '.[].Instances[] |= . + {"State": ($states[.InstanceId] // "unknown")}' SomeFile1.json
[
  {
    "DNSName": "CLB-test-112a877451.ap-northeast-1.elb.amazonaws.com",
    "Instances": [
      {
        "InstanceId": "i-0886ed703de64028a",
        "State": "InService"
      }
    ]
  },
  {
    "DNSName": "CLB-test1-156925981.ap-northeast-1.elb.amazonaws.com",
    "Instances": [
      {
        "InstanceId": "i-0561634c4g3b4fa25",
        "State": "NOTInService"
      }
    ]
  }
]


Answer 2:

由于第二个文件的内容显然意在从INSTANCEID定义映射到国家,让我们假设到JQ的以下调用启动:

jq --argfile dict SomeFile2.json -f program.jq SomeFile1.json

接下来,让我们创建一个合适的解释:

reduce $dict[] as $x ({}; . + ($x|{(.InstanceId): .State}))) as $d

现在剩下的就是容易:

map(.Instances |= map(. + {State: $d[.InstanceId]}))

把拼在一起的program.jq:

(reduce $dict[] as $x ({}; . + ($x|{(.InstanceId): .State}))) as $d
| map(.Instances |= map(. + {State: $d[.InstanceId]}))

备择方案

字典如上可以在不使用被构造reduce ,如下所示:

($dict | map( {(.InstanceId): .State}) | add) as $d

另一种替代方法是使用INDEX/2

(INDEX($dict[]; .InstanceId) | map_values(.State))) as $d

如果您的JQ没有INDEX/2 ,你可以从它的SNARF高清https://raw.githubusercontent.com/stedolan/jq/master/src/builtin.jq



文章来源: how to merge two JSON objects using jq?
标签: json bash shell jq