从另一个深度的另一个文件中检索一个键值

Retrieve one key value from another file at another depth

我有两个 json 文件(这些来自 AWS)。一个是在服务器状态更改 (state.json) 后从亚马逊返回的,另一个包含实例的详细信息,包括特定标签(标签称为“名称”,值包含服务器的主机名)- 文件是在我的示例中称为 instance.json。我正在尝试编写一些 jq,它使用从状态中检索到的 instanceID 来查询实例详细信息文档(使用相同的 instanceID 键)。我想如果我能在正确的位置将主机名标签添加到状态文档中,那将是理想的...

这通常是我可能能够做到的,但是键在 json 中的深度不同,我不知道如何检索不同的 depth/matching 键。 (如果您熟悉 aws,您会知道服务器状态在实例中也是 also,但是我正在更改状态并且不希望进行 3 次亚马逊调用)。

下面的一些示例 json:

instance.json(文件很大,我把无用的部分都删掉了,结构保持不变):

{
  "Reservations": [
    {
      "Instances": [
        {
          "InstanceId": "i-1",
          "Tags": [
            {
              "Value": "hostname1",
              "Key": "Name"
            }
          ],
          "AmiLaunchIndex": 0
        }
      ],
      "ReservationId": "r-1",
      "Groups": []
    },
    {
      "Instances": [
        {
          "InstanceId": "i-2",
          "Tags": [
            {
              "Value": "hostname2",
              "Key": "Name"
            }
          ],
          "AmiLaunchIndex": 0
        }
      ],
      "ReservationId": "r-1",
      "Groups": []
    },
    {
      "Instances": [
        {
          "InstanceId": "i-3",
          "Tags": [
            {
              "Value": "hostname3",
              "Key": "Name"
            }
          ],
          "AmiLaunchIndex": 0
        }
      ],
      "ReservationId": "r-1",
      "Groups": []
    }
  ]
}

state.json:

{
    "StoppingInstances": [
        {
            "CurrentState": {
                "Code": 80,
                "Name": "stopped"
            },
            "InstanceId": "i-1",
            "PreviousState": {
                "Code": 80,
                "Name": "stopped"
            }
        },
        {
            "CurrentState": {
                "Code": 80,
                "Name": "stopped"
            },
            "InstanceId": "i-2",
            "PreviousState": {
                "Code": 80,
                "Name": "stopped"
            }
        },
        {
            "CurrentState": {
                "Code": 80,
                "Name": "stopped"
            },
            "InstanceId": "i-3",
            "PreviousState": {
                "Code": 80,
                "Name": "stopped"
            }
        }
    ]
}

理想的输出(如果可能):

{
  "StoppingInstances": [
      {
          "CurrentState": {
              "Code": 80,
              "Name": "stopped"
          },
          "InstanceId": "i-1",
          "Hostname": "hostname1",
          "PreviousState": {
              "Code": 80,
              "Name": "stopped"
          }
      },
      {
          "CurrentState": {
              "Code": 80,
              "Name": "stopped"
          },
          "InstanceId": "i-2",
          "Hostname": "hostname2",
          "PreviousState": {
              "Code": 80,
              "Name": "stopped"
          }
      },
      {
          "CurrentState": {
              "Code": 80,
              "Name": "stopped"
          },
          "InstanceId": "i-3",
          "Hostname": "hostname3",
          "PreviousState": {
              "Code": 80,
              "Name": "stopped"
          }
      }
  ]
}

要根据与 state.json 共享的 ID 查询 instance.json 中的特定标签,您可以通过使用变量和 select 函数比较它们的公共 ID 来遍历目标。

jq -r --argfile state state.json --arg tag "Name" '
  $state.StoppingInstances[].InstanceId as $id
  | .Reservations[].Instances[]
  | select(.InstanceId == $id).Tags[]
  | select(.Key == $tag).Value
' instance.json
hostname1
hostname2
hostname3

要将 instance.json 中的记录与 state.json 中的项目合并,您可以使用 INDEXJOIN 内置函数:

jq --argfile instance instance.json '
  .StoppingInstances |= JOIN(
    INDEX($instance.Reservations[].Instances[]; .InstanceId); .InstanceId
  )
' state.json
{
  "StoppingInstances": [
    [
      {"CurrentState":{"Code":80,"Name":"stopped"},"InstanceId":"i-1","PreviousState":{"Code":80,"Name":"stopped"}},
      {"InstanceId":"i-1","Tags":[{"Value":"hostname1","Key":"Name"}],"AmiLaunchIndex":0}
    ],
    [
      {"CurrentState":{"Code":80,"Name":"stopped"},"InstanceId":"i-2","PreviousState":{"Code":80,"Name":"stopped"}},
      {"InstanceId":"i-2","Tags":[{"Value":"hostname2","Key":"Name"}],"AmiLaunchIndex":0}
    ],
    [
      {"CurrentState":{"Code":80,"Name":"stopped"},"InstanceId":"i-3","PreviousState":{"Code":80,"Name":"stopped"}},
      {"InstanceId":"i-3","Tags":[{"Value":"hostname3","Key":"Name"}],"AmiLaunchIndex":0}
    ]
  ]
}

这是一个直接使用 INDEX 的方法。它假定调用以下形式,当然可能有不同的变化:

jq -n --argfile state state.json --argfile instance instance.json -f program.jq

其中 program.jq 包含:

INDEX($instance.Reservations[].Instances[]; .InstanceId)
| map_values(.Tags|from_entries.Name) as $dict
| $state
| .StoppingInstances |= map(. + {Hostname: $dict[.InstanceId]})

如果您不确定.InstanceId在instance.json中的位置,您可以修改上面的内容如下:

INDEX($instance | .. | objects | select(has("Instances")) | .Instances[]; 
      .InstanceId)
| map_values(.Tags|from_entries.Name) as $dict
| $state
| .StoppingInstances |= map(. + {Hostname: $dict[.InstanceId]})