【jq】配下に特定の文字列を持つオブジェクトを取得する

## はじめに

以下のJSONから、「配下に特定のメールアドレス(`userA@example.com`)を持つrequestParametersの一覧」を取得したかったので、調べてみました。

```sample.json
[
  {
    "requestParameters": {
      "emailAddress": "userA@example.com"
    }
  },
  {
    "requestParameters": {
      "identities": [
        "userB@example.com",
        "userA@example.com"
      ]
    }
  },
  {
    "requestParameters": {
      "templateName": "templateNameC",
      "emailAddress": "userC@example.com"
    }
  }
]
```

具体的には、上のJSONを以下に整形します。

```result.json
[
  {
    "requestParameters": {
      "emailAddress": "userA@example.com"
    }
  },
  {
    "requestParameters": {
      "identities": [
        "userB@example.com",
        "userA@example.com"
      ]
    }
  }
]

```

## 結論

こんな感じで取得できました。

```sh
$ cat sample.json | \
   jq '[.[] | select(.requestParameters[] | if type=="array" then .[] else . end | . == "userA@example.com")]'

[
  {
    "requestParameters": {
      "emailAddress": "userA@example.com"
    }
  },
  {
    "requestParameters": {
      "identities": [
        "userB@example.com",
        "userA@example.com"
      ]
    }
  }
]
```

## 詳細

上のフィルターに改行を入れると、以下のようになります。

```sh
$ cat sample.json | \
   jq '[
          .[] | select(
                .requestParameters[]
                  | if type=="array" then .[] else . end
                  | . == "userA@example.com"
              )
       ]'
```

順に見ていきます。

### `.requestParameters[]`

配列の各要素を取得するのに使う`[]`ですが、オブジェクトに対しても使えます。
その場合、オブジェクトの全てのValueを取得できます。

[jq Manual](https://stedolan.github.io/jq/manual/)には以下のように記述されています。

> You can also use this on an object, and it will return all the values of the object.

```簡単な例.sh
$ echo '{"a": 1, "b": 2}' | jq '.[]'

1
2
```

```今回の例.sh
$ cat sample.json | jq '.[].requestParameters[]'

"userA@example.com"
[
  "userB@example.com",
  "userA@example.com"
]
"templateNameC"
"userC@example.com"
```

### `if type=="array" then .[] else . end`

よくあるif文です。
入力が配列(`type=="array"`)であれば配列の各要素(`.[]`)を返し、そうでなければ入力(`.`)を返します。

```簡単な例.sh
$ echo [1,2] | jq 'if type=="array" then .[] else . end'
1
2

$ echo 1 | jq 'if type=="array" then .[] else . end'
1
```

```今回の例.sh
$ cat sample.json | jq '.[].requestParameters[] | if type=="array" then .[] else . end'

"userA@example.com"
"userB@example.com"
"userA@example.com"
"templateNameC"
"userC@example.com"
```

### `. == "userA@example.com"`

入力値が`"userA@example.com"`に一致するか確認する

```簡単な例.sh
$ echo '["userA@example.com", "userB@example.com"]' \
   | jq '.[] | . == "userA@example.com"'
true
false
```

```今回の例.sh
$ cat sample.json \
  | jq '.[].requestParameters[]
  | if type=="array" then .[] else . end
  | . == "userA@example.com"'

true
false
true
false
false
```

### select(boolean_expression)
入力値に対して、式`boolean_expression`がtrueを返す場合、その入力値をそのまま返却します。
trueを返さない場合は何も返しません。

```簡単な例.sh
$ echo [1,5,3,0,7] | jq '.[] | select(. >= 5)'
5
7
```

```今回の例.sh
$ cat sample.json | \
   jq '   .[] | select(
                .requestParameters[]
                  | if type=="array" then .[] else . end
                  | . == "userA@example.com"
              )'

{
  "requestParameters": {
    "emailAddress": "userA@example.com"
  }
}
{
  "requestParameters": {
    "identities": [
      "userB@example.com",
      "userA@example.com"
    ]
  }
}
```

## 参考:
- [jq Manual (development version)](https://stedolan.github.io/jq/manual/)
- [linux - Using jq to fetch key value from json output - Stack Overflow](https://stackoverflow.com/questions/39798542/using-jq-to-fetch-key-value-from-json-output)