Search code examples
jsonjmespath

JMESPath to flatten complicated query array results


Given the JSON

{
  "Reservations": [
    {
      "Groups": [],
      "Instances": [
        {
          "AmiLaunchIndex": 0,
          "ImageId": "ami-0abcdef1234567890",
          "InstanceId": "i-1234567890abcdef0",
          "InstanceType": "t2.micro",
          "KeyName": "MyKeyPair",
          "LaunchTime": "2018-05-10T08:05:20.000Z",
          "Monitoring": {
            "State": "disabled"
          },
          "Placement": {
            "AvailabilityZone": "us-east-2a",
            "GroupName": "",
            "Tenancy": "default"
          },
          "PrivateDnsName": "ip-10-0-0-157.us-east-2.compute.internal",
          "PrivateIpAddress": "10.0.0.157",
          "ProductCodes": [],
          "PublicDnsName": "",
          "State": {
            "Code": 0,
            "Name": "pending"
          },
          "StateTransitionReason": "",
          "SubnetId": "subnet-04a636d18e83cfacb",
          "VpcId": "vpc-1234567890abcdef0",
          "Architecture": "x86_64",
          "BlockDeviceMappings": [],
          "ClientToken": "",
          "EbsOptimized": false,
          "Hypervisor": "xen",
          "NetworkInterfaces": [
            {
              "Attachment": {
                "AttachTime": "2018-05-10T08:05:20.000Z",
                "AttachmentId": "eni-attach-0e325c07e928a0405",
                "DeleteOnTermination": true,
                "DeviceIndex": 0,
                "Status": "attaching"
              },
              "Description": "",
              "Groups": [
                {
                  "GroupName": "MySecurityGroup",
                  "GroupId": "sg-0598c7d356eba48d7"
                }
              ],
              "Ipv6Addresses": [],
              "MacAddress": "0a:ab:58:e0:67:e2",
              "NetworkInterfaceId": "eni-0c0a29997760baee7",
              "OwnerId": "123456789012",
              "PrivateDnsName": "ip-10-0-0-157.us-east-2.compute.internal",
              "PrivateIpAddress": "10.0.0.157",
              "PrivateIpAddresses": [
                {
                  "Primary": true,
                  "PrivateDnsName": "ip-10-0-0-157.us-east-2.compute.internal",
                  "PrivateIpAddress": "10.0.0.157"
                }
              ],
              "SourceDestCheck": true,
              "Status": "in-use",
              "SubnetId": "subnet-04a636d18e83cfacb",
              "VpcId": "vpc-1234567890abcdef0",
              "InterfaceType": "interface"
            }
          ],
          "RootDeviceName": "/dev/xvda",
          "RootDeviceType": "ebs",
          "SecurityGroups": [
            {
              "GroupName": "MySecurityGroup",
              "GroupId": "sg-0598c7d356eba48d7"
            }
          ],
          "SourceDestCheck": true,
          "StateReason": {
            "Code": "pending",
            "Message": "pending"
          },
          "Tags": [],
          "VirtualizationType": "hvm",
          "CpuOptions": {
            "CoreCount": 1,
            "ThreadsPerCore": 1
          },
          "CapacityReservationSpecification": {
            "CapacityReservationPreference": "open"
          },
          "MetadataOptions": {
            "State": "pending",
            "HttpTokens": "optional",
            "HttpPutResponseHopLimit": 1,
            "HttpEndpoint": "enabled"
          }
        }
      ],
      "OwnerId": "123456789012",
      "ReservationId": "r-02a3f596d91211712"
    }
  ]
}

and the JMESPath query

Reservations[].Instances[].{KeyName: KeyName, InstanceId: InstanceId, GroupId: NetworkInterfaces[].Groups[].GroupId, SubnetId: NetworkInterfaces[].SubnetId}

it will yield:

[
  {
    "KeyName": "MyKeyPair",
    "InstanceId": "i-1234567890abcdef0",
    "GroupId": [
      "sg-0598c7d356eba48d7"
    ],
    "SubnetId": [
      "subnet-04a636d18e83cfacb"
    ]
  }
]

How can I just get the first item of the arrays, and flatten the final result to:

[
  {
    "KeyName": "MyKeyPair",
    "InstanceId": "i-1234567890abcdef0",
    "GroupId": "sg-0598c7d356eba48d7",
    "SubnetId": "subnet-04a636d18e83cfacb"
  }
]

I tried to place 0 into those []s (like GroupId: NetworkInterfaces[0].Groups[0].GroupId[0]), or use GroupId: NetworkInterfaces[].Groups[].GroupId[], but nothing seems to be working.


Solution

  • Your actual attempts are not working because you trying to address some properties as arrays.

    In your attempt

    NetworkInterfaces[0].Groups[0].GroupId[0]
    

    NetworkInterfaces and Groups are indeed arrays, so you need to address them with an array notation. But the resulting group is an object and GroupId is one of its property.

    So, you'll need to address it using

    NetworkInterfaces[0].Groups[0].GroupId
    

    The exact same goes for SubnetId.

    So, the end query would be:

    Reservations[].Instances[].{
      KeyName: KeyName, 
      InstanceId: InstanceId, 
      GroupId: NetworkInterfaces[0].Groups[0].GroupId, 
      SubnetId: NetworkInterfaces[0].SubnetId
    }
    

    That yields your expected:

    [
      {
        "KeyName": "MyKeyPair",
        "InstanceId": "i-1234567890abcdef0",
        "GroupId": "sg-0598c7d356eba48d7",
        "SubnetId": "subnet-04a636d18e83cfacb"
      }
    ]