【Ansible】json_queryの活用～2回目：to_string/max_by/min_by/length/type～

### はじめに

<バージョン>
ansible 2.9.7
jmespath 0.10.0

Ansibleのjson_queryフィルタは変数の抽出が便利でよく使います。
[JMESPath Specification(built-in-functions)](https://jmespath.org/specification.html#built-in-functions)にfunctionの一覧が載っているので、
使えそうなのを紹介していきます。

### 1. 使用する変数

今回は以下のファイルから変数を取得し、json_queryで特定の部分を抽出します。

```yaml：sample_vars.yml
---
sample:
  - id: 1
    index: 1
    data: []
  - id: 2
    index: "1"
    data: ["a"]
  - id: 3
    index: "3"
    data: ["a", "b"]
```


### 2. Playbook紹介

今回は以下5パターンを紹介します。functionを使い、変数sample内の3つのデータから
指定したデータを抽出します。

| パターン | function | 用途 | 
|:-----------|:------------|:------------|
| 1 | to_string | データ型をstringに変換する |
| 2 | max_by | 特定のキーが最大のデータを抽出する |
| 3 | min_by | 特定のキー最小のデータを抽出する |
| 4 | length | 特定のキーの要素数を抽出する |
| 5 | type | 特定のキーのデータ型を抽出する |

```yaml:test_json_query.yml
---
- name: "TEST json_query"
  hosts: localhost
  gather_facts: false
  vars_files:
    - sample_vars.yml 
  tasks:
    - name: "pattern1 - to_string: {{ query_string }}"
      debug:
        var: sample | json_query(query_string)
      vars:
        query_string: "[?index==to_string(`1`)]"    # indexが1(文字列)のデータを抽出 - ポイント（1）

    - name: "pattern2 - max_by: {{ query_string }}"
      debug:
        var: sample | json_query(query_string)
      vars:
        query_string: "max_by([], &id)"             # idが最大のデータを抽出

    - name: "pattern3 - min_by: {{ query_string }}"
      debug:
        var: sample | json_query(query_string)
      vars:
        query_string: "min_by([], &id)"             # idが最小のデータを抽出

    - name: "pattern4 - length: {{ query_string }}"
      debug:
        var: sample | json_query(query_string)
      vars:
        query_string: "[?length(data) > `0`]"       # dataの要素数 > 0 のデータを抽出

    - name: "pattern5 - type: {{ query_string }}"
      debug:
        var: sample | json_query(query_string)    
      vars:
        query_string: "[?type(index) == `string`]"  # indexのデータ型がstringのデータを抽出 - ポイント（2）
```

__ポイント__

（1）to_string(\`1\`)と記述することで、to_string内は文字列として認識される。 
　　query_string: "[?index==\`1\`]" だと1という数字に認識されてしまうので注意。
（2）typeの書き方については、[JMESPath Specification(type)](https://jmespath.org/specification.html#type)を参照。

### 3. 実行結果

想定通りにデータを抽出することが出来ました。

```text:出力
(venv) [develop@centos-develop ansible_test]$ ansible-playbook test_json_query.yml 

PLAY [TEST json_query] *********************************************************

TASK [pattern1 - to_string: [?index==to_string(`1`)]] **************************
ok: [localhost] => {
    "sample | json_query(query_string)": [
        {
            "data": [
                "a"
            ],
            "id": 2,
            "index": "1"
        }
    ]
}

TASK [pattern2 - max_by: max_by([], &id)] **************************************
ok: [localhost] => {
    "sample | json_query(query_string)": {
        "data": [
            "a",
            "b"
        ],
        "id": 3,
        "index": "3"
    }
}

TASK [pattern3 - min_by: min_by([], &id)] **************************************
ok: [localhost] => {
    "sample | json_query(query_string)": {
        "data": [],
        "id": 1,
        "index": 1
    }
}

TASK [pattern4 - length: [?length(data) > `0`]] ********************************
ok: [localhost] => {
    "sample | json_query(query_string)": [
        {
            "data": [
                "a"
            ],
            "id": 2,
            "index": "1"
        },
        {
            "data": [
                "a",
                "b"
            ],
            "id": 3,
            "index": "3"
        }
    ]
}

TASK [pattern5 - type: [?type(index) == `string`]] *****************************
ok: [localhost] => {
    "sample | json_query(query_string)": [
        {
            "data": [
                "a"
            ],
            "id": 2,
            "index": "1"
        },
        {
            "data": [
                "a",
                "b"
            ],
            "id": 3,
            "index": "3"
        }
    ]
}

PLAY RECAP *********************************************************************
localhost                  : ok=5    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0 
```

### 参考資料

[JMESPath Specification](https://jmespath.org/specification.html)

### 関連記事

[【Ansible】json_queryの活用～1回目：contain/starts_with/ends_with/and/or～](https://qiita.com/masa2223/items/0e726e7cfe8667448ac9)