AWS CLIの--queryについて殴り書き

## この記事
AWS CLIのqueryオプションと色々格闘した時に知ったことのメモです

## 前知識
AWS CLIのqueryオプションは[JMESPath](https://jmespath.org/)を用いています
[こちらのサイト](https://jmespath.org/tutorial.html)で色々とお試しできます

## 対象
```
aws ec2 describe-instances --filters Name=tag:Owner,Values=Dohara
```
- [describe-instancesコマンド](https://docs.aws.amazon.com/cli/latest/reference/ec2/describe-instances.html)
- インスタンスは2台で、それぞれのNameタグは以下のとおりです
    - dohara-dev-xxx
    - dohara-dev-yyy
- 見やすさのため、必要な項目以外は省略しています

```
{
  "Reservations": [
    {
      "Groups": [],
      "Instances": [
        {
          ...
          
          "InstanceId": "i-06c93dcc7a43c9b2f",
          
          ...
          
          "BlockDeviceMappings": [
            {
              "DeviceName": "/dev/xvda",
              "Ebs": {
                "AttachTime": "2022-03-29T02:10:09+00:00",
                "DeleteOnTermination": true,
                "Status": "attached",
                "VolumeId": "vol-06c873b06b2a76350"
              }
            }
          ],
          
          ...
          
          "Tags": [
            {
              "Key": "Name",
              "Value": "dohara-dev-xxx"
            },
            {
              "Key": "cloudpack",
              "Value": "Dohara"
            },
            {
              "Key": "Owner",
              "Value": "Dohara"
            }
          ],
          
          ...
          
          "CpuOptions": {
            "CoreCount": 1,
            "ThreadsPerCore": 1
          },
          
          ...
          
        }
      ],

      ...

    },
    {
      "Groups": [],
      "Instances": [
        {
          
          ...
          
          "InstanceId": "i-0e89607f349c14819",
          
          ...
          
          "BlockDeviceMappings": [
            {
              "DeviceName": "/dev/xvda",
              "Ebs": {
                "AttachTime": "2022-03-29T04:47:24+00:00",
                "DeleteOnTermination": true,
                "Status": "attached",
                "VolumeId": "vol-0e0e4e18692e57ba8"
              }
            }
          ],
          
          ...
          
          "Tags": [
            {
              "Key": "cloudpack",
              "Value": "Dohara"
            },
            {
              "Key": "Owner",
              "Value": "Dohara"
            },
            {
              "Key": "Name",
              "Value": "dohara-dev-yyy"
            }
          ],
          
          ...
          
          "CpuOptions": {
            "CoreCount": 1,
            "ThreadsPerCore": 1
          },
          
          ...
          
        }
      ],

      ...

    }
  ]
}
```

## リストとネスト
### [リスト](https://docs.aws.amazon.com/cli/latest/userguide/cli-usage-filter.html#cli-usage-filter-client-side-select-list)

```
{
  "xxx": [
    {
      "yyy": "hoge"
    },
    {
    
      ...
    
    },
    
    ...
    
  ]
}
```
`[]`で囲われた各要素はリストとなります

`xxx[<Index>].yyy`とすることで取得可能です
- `xxx[]`と`xxx[*]`で少し出力が異なります
    - `xxx[]`での出力をフラット化するというらしいです（[参考](https://docs.aws.amazon.com/cli/latest/userguide/cli-usage-filter.html#cli-usage-filter-client-side-specific-flattening)）

#### 例
`xxx[]`パターン 
```
aws ec2 describe-instances --filters Name=tag:Owner,Values=Dohara --query "Reservations[].Instances[].Tags[]"
```
```
[
  {
    "Key": "Name",
    "Value": "dohara-dev-xxx"
  },
  {
    "Key": "cloudpack",
    "Value": "Dohara"
  },
  {
    "Key": "Owner",
    "Value": "Dohara"
  },
  {
    "Key": "cloudpack",
    "Value": "Dohara"
  },
  {
    "Key": "Owner",
    "Value": "Dohara"
  },
  {
    "Key": "Name",
    "Value": "dohara-dev-yyy"
  }
]
```

`xxx[*]`パターン 
```
aws ec2 describe-instances --filters Name=tag:Owner,Values=Dohara --query "Reservations[].Instances[*].Tags[*]"
```
```
[
  [
    [
      {
        "Key": "Name",
        "Value": "dohara-dev-xxx"
      },
      {
        "Key": "cloudpack",
        "Value": "Dohara"
      },
      {
        "Key": "Owner",
        "Value": "Dohara"
      }
    ]
  ],
  [
    [
      {
        "Key": "cloudpack",
        "Value": "Dohara"
      },
      {
        "Key": "Owner",
        "Value": "Dohara"
      },
      {
        "Key": "Name",
        "Value": "dohara-dev-yyy"
      }
    ]
  ]
]
```

### [ネスト](https://docs.aws.amazon.com/cli/latest/userguide/cli-usage-filter.html#cli-usage-filter-client-side-nested)
```
{
  "xxx": {
    "yyy": {
      "zzz": "hoge"
    }
  }
}
```
`{}`で囲っていくことで要素がネストされていきます

`xxx.yyy.zzz`とすることで取得可能です

#### 例
```
aws ec2 describe-instances --filters Name=tag:Owner,Values=Dohara --query "Reservations[].Instances[].BlockDeviceMappings[].Ebs.VolumeId"
```
```
[
  "vol-06c873b06b2a76350",
  "vol-0e0e4e18692e57ba8"
]
```

## ラベル
クエリ結果は基本的にValueのみが出力され、Keyは出力されません
※ Keyも出力する方法があったら、教えていただけたらありがたいです
そこで、それぞれのクエリ結果に対してラベルを付与できます

#### 基本形
```
{
  "xxx": {
    "yyy": "hoge"
  }
}
```

`xxx.yyy`の場合の出力
```
"hoge"
```
`xxx.{yyy: yyy}`の場合の出力
```
{
  "yyy": "hoge"
}
```

#### 例
クエリ結果「VolumeId」にラベル「hogehoge」を付与して出力
```
aws ec2 describe-instances --filters Name=tag:Owner,Values=Dohara --query "Reservations[].Instances[].BlockDeviceMappings[].Ebs.{hogehoge: VolumeId}"
```
```
[
  {
    "hogehoge": "vol-06c873b06b2a76350"
  },
  {
    "hogehoge": "vol-0e0e4e18692e57ba8"
  }
]
```

## 比較
特定のValueに対して比較演算子を用いることで、リストにおいて対象の絞り込みが可能です
例えば、全タグのうちNameタグのみを出力するなど

#### 基本形
```
{
  "xxx": [
    {
      "yyy": "a1",
      "zzz": "a2"
    },
    {
      "yyy": "b1",
      "zzz": "b2"
    }
  ]
}
```

`xxx[?yyy=='a1']`で絞り込み可能
```
[
  {
    "yyy": "a1",
    "zzz": "a2"
  }
]
```

- 文字列（ここでは「a1」）は`'`または`` ` ``で囲む必要があります

#### 例
タグのキーが「Name」の場合のみ、タグを出力
```
aws ec2 describe-instances --filters Name=tag:Owner,Values=Dohara --query "Reservations[].Instances[].Tags[?Key=='Name']"
```

```
[
  [
    {
      "Key": "Name",
      "Value": "dohara-dev-xxx"
    }
  ],
  [
    {
      "Key": "Name",
      "Value": "dohara-dev-yyy"
    }
  ]
]
```

#### 補足
##### 複数条件を組み合わせる場合
AND : `xxx[?(yyy=='a1' && zzz=='a2')]`
OR : `xxx[?(yyy=='a1' || yyy=='b1')]`
###### 例
タグのキーが「Name」**または**「Owner」の場合のみ、タグを出力
```
aws ec2 describe-instances --filters Name=tag:Owner,Values=Dohara --query "Reservations[].Instances[].Tags[?(Key=='Name' || Key=='Owner')]"
```
```
[
  [
    {
      "Key": "Name",
      "Value": "dohara-dev-xxx"
    },
    {
      "Key": "Owner",
      "Value": "Dohara"
    }
  ],
  [
    {
      "Key": "Owner",
      "Value": "Dohara"
    },
    {
      "Key": "Name",
      "Value": "dohara-dev-yyy"
    }
  ]
]
```

## 関数
JMESPathでは様々な関数が用意されています
### contains
特定の文字列を含むかを判定します

#### 例
タグの値に「xxx」が含まれている場合のみ、タグを出力
```
aws ec2 describe-instances --filters Name=tag:Owner,Values=Dohara --query "Reservations[].Instances[].Tags[?contains(Value, 'xxx')]"
```
```
[
  [
    {
      "Key": "Name",
      "Value": "dohara-dev-xxx"
    }
  ],
  []
]
```

### sort_by
指定した要素で出力結果をソートします

#### 例
タグをキーでソートして出力
```
aws ec2 describe-instances --filters Name=tag:Owner,Values=Dohara --query "Reservations[].Instances[].sort_by(Tags, &Key)"
```
```
[
  [
    {
      "Key": "Name",
      "Value": "dohara-dev-xxx"
    },
    {
      "Key": "Owner",
      "Value": "Dohara"
    },
    {
      "Key": "cloudpack",
      "Value": "Dohara"
    }
  ],
  [
    {
      "Key": "Name",
      "Value": "dohara-dev-yyy"
    },
    {
      "Key": "Owner",
      "Value": "Dohara"
    },
    {
      "Key": "cloudpack",
      "Value": "Dohara"
    }
  ]
]
```
- sort_by未使用時は[リスト](#リストとネスト)の例を参照してください
- `reverse(sort_by())`とすることで逆転させることが可能です

## その他
### データ型
各値にはstringやnuberなどの型が定義されており、そこを意識しないと時折沼にハマります
`type()`を用いることで確認可能です

```
aws ec2 describe-instances --filters Name=tag:Owner,Values=Dohara --query "Reservations[].Instances[].{InstanceId: InstanceId, type_InstanceId: type(InstanceId), CoreCount: CpuOptions.CoreCount, type_CoreCount: type(CpuOptions.CoreCount)}"
```
```
[
  {
    "InstanceId": "i-06c93dcc7a43c9b2f",
    "type_InstanceId": "string",
    "CoreCount": 1,
    "type_CoreCount": "number"
  },
  {
    "InstanceId": "i-0e89607f349c14819",
    "type_InstanceId": "string",
    "CoreCount": 1,
    "type_CoreCount": "number"
  }
]
```

また、`to_string()`などの型変換用の関数も存在します

## 参考
- [JMESPath](https://jmespath.org/)
- [JMESPath Tutorial](https://jmespath.org/tutorial.html)
- [describe-instances](https://docs.aws.amazon.com/cli/latest/reference/ec2/describe-instances.html)
- [Filtering AWS CLI output](https://docs.aws.amazon.com/cli/latest/userguide/cli-usage-filter.html)