「jqめちゃくちゃ便利じゃん😂」と感動することが多いので使い方を調べた

この記事は、[ニフティグループ Advent Calendar 2021](https://qiita.com/advent-calendar/2021/nifty) 21日目の記事です。

## はじめに
皆さんはjqを活用していますでしょうか？
私は、業務の中でJSONデータを扱うことが多く、巨大なJSONデータの一部を抽出する時や整形して企画チームのメンバーに共有する時などにお世話になっております。
使うたびに、「そんなこと出来るの！？すげえ😂」と感動していました。

そこで、アドベントカレンダーの執筆を機会に「自分用のメモを作ってしまおう😚」と考え記事を書くことにしました。

使う頻度が高そうだと判断したもののみ抜粋しました。その点をご了承くださいませ。

## 環境

- macOS Catalina version 10.15.6
- jq version 1.6

以下の内容は公式ドキュメントを参考にしています。詳しく知りたい方はこちらを参考にしてください。
[jq](https://stedolan.github.io/jq/)

## インストール方法

brewで入れることができます。

```bash
$ brew install jq
```

[jq — Homebrew Formulae](https://formulae.brew.sh/formula/jq)

macOS以外の方は以下のページを参考にしてください。

[Download jq](https://stedolan.github.io/jq/download/)

## テスト用データ

以下のサンプルデータを使用します。

```bash:user.json
{
    "name": "Tanaka",
    "age": 25,
    "address": {
        "state": "tokyo",
        "city": "shinjuku"
    }
}
```

```bash:users.json
[
    {
        "name": "Tanaka",
        "age": 25,
        "address": {
            "state": "tokyo",
            "city": "shinjuku"
        }
    },
    {
        "name": "Suzuki",
        "age": 30,
        "address": {
            "state": "chiba",
            "city": "funabashi"
        }
    }
]
```

## フォーマット

jqはデフォルトでJSONをフォーマットしてくれます。
以下の記述で、フォーマットのみを行います。

```bash
$ cat user.json | jq .
{
  "name": "Tanaka",
  "age": 25,
  "address": {
      "state": "tokyo",
      "city": "shinjuku"
  }
}
```

## 基本的な絞り込み

### 特定のキーの値のみ取得する

以下の記述で、特定のキーの値のみを取得できます。
ユーザのnameを取得してみます。

```bash
$ cat user.json | jq '.name'
"Tanaka"
```

複数のキーをドットで連結することにより、ネストされた値を取得することができます。
addressのstateを取得してみます。

```bash
$ cat user.json | jq '.address.state'
"tokyo"
```

配列についてはこの後解説しますが、要素ごとの値も取得することができます。
`|`(パイプ)区切りにすることで、左側の処理から実行されます。
配列を取得した後に配列ごとにageを取得してみます。

```bash
$ cat users.json | jq '.[] | .age'
25
30
```

キーも残す場合は以下のように記述します。

```bash
$ cat users.json | jq '.[] | {name, age}'
{
  "name": "Tanaka",
  "age": 25
}
{
  "name": "Suzuki",
  "age": 30
}
```

### 複数のキーの値を取得する

条件がカンマで区切られている場合は、同じ入力が両方に行われそれぞれの結果が順番に出力されます。
今回であれば、

1. ageを取得
2. addressの中のstateを取得

の順番で処理されています。

```bash
$ cat user.json | jq '.age,.address.state'
25
"tokyo"
```

### 配列を取得する

以下の記述で、配列を取得できます。
全ユーザの情報を取得してみます。

```bash
$ cat users.json | jq '.[]'
{
  "name": "Tanaka",
  "age": 25,
  "address": {
    "state": "tokyo",
    "city": "shinjuku"
  }
}
{
  "name": "Suzuki",
  "age": 30,
  "address": {
    "state": "chiba",
    "city": "funabashi"
  }
}
```

### 配列の特定の要素のみ取得する

インデックスを指定することで、配列の一部を取得することができます。
2人目のユーザ情報のみ取得してみます。

```bash
$ cat users.json | jq '.[1]'
{
  "name": "Suzuki",
  "age": 30,
  "address": {
    "state": "chiba",
    "city": "funabashi"
  }
}
```

## 配列の構築

以下の記述で配列を構築できます。
ユーザごとのaddressを取得し、配列を構築してみます。

```bash
$ cat users.json | jq ['.[] | .address']
[
  {
    "state": "tokyo",
    "city": "shinjuku"
  },
  {
    "state": "chiba",
    "city": "funabashi"
  }
]
```

## オブジェクトの構築

以下の記述でオブジェクトを構築できます。
ユーザごとのnameを取得し、namesというキーの値に設定してみます。

```bash
$ cat users.json | jq '{"names": [.[] | .name]}'
{
  "names": [
    "Tanaka",
    "Suzuki"
  ]
}
```

## 計算

### 四則演算

四則演算は一通り実行できます。
ユーザの年齢に50加えてみます。

```bash
$ cat user.json | jq '.age+50'
75
```

### 配列の合計を取得する

配列に対して、 `add関数` を使用することで合計値を取得することができます。
ageの合計を取得してみます。

```bash
$ cat users.json | jq '[.[] | .age] | add'
55
```

### 配列の平均を取得する

length関数については後で解説しますが、配列の長さで割ることで配列の平均を取得することができます。
ageの平均を取得してみます。

```bash
$ cat users.json | jq '[.[] | .age] | add / length'
27.5
```

## その他の組み込み関数

### 長さを取得する

`length関数` を使用することで、長さを取得することができます。配列の場合は要素数が取得できます。
ユーザの数を取得してみます。

```bash
$ cat users.json | jq '.| length'
2
```

### キーの一覧を取得する

`keys関数` を使用することで、オブジェクトのキーを一覧で取得できます。

```bash
$ cat user.json | jq 'keys'
[
  "address",
  "age",
  "name"
]
```

### 特定のキーを削除する

`del関数` を使用することで、キーの一部を削除することができます。
addressを削除してみます。

```bash
$ cat user.json | jq 'del(.address)'
{
  "name": "Tanaka",
  "age": 25
}
```

配列に適用することも可能です。

```bash
$ cat users.json | jq '.[] | del(.address)'
{
  "name": "Tanaka",
  "age": 25
}
{
  "name": "Suzuki",
  "age": 30
}
```

### 条件で絞り込んで取得する

`select関数` を使用することで、条件で絞り込んで取得することができます。
ageが25のユーザのみ取得してみます。

```bash
$ cat users.json | jq '.[] | select(.age == 25)'
{
  "name": "Tanaka",
  "age": 25,
  "address": {
    "state": "tokyo",
    "city": "shinjuku"
  }
}
```

### ソート

`sort_by関数`を利用することで、特定の値をもとに昇順ソートできます。
ageをもとに昇順ソートしてみます。

```bash
$ cat users.json | jq 'sort_by(.age)'
[
  {
    "name": "Tanaka",
    "age": 25,
    "address": {
      "state": "tokyo",
      "city": "shinjuku"
    }
  },
  {
    "name": "Suzuki",
    "age": 30,
    "address": {
      "state": "chiba",
      "city": "funabashi"
    }
  }
]
```

降順ソートについては、 `reverse関数`を使用することで実現できます。

```bash
$cat users.json | jq 'sort_by(.age) | reverse'
[
  {
    "name": "Suzuki",
    "age": 30,
    "address": {
      "state": "chiba",
      "city": "funabashi"
    }
  },
  {
    "name": "Tanaka",
    "age": 25,
    "address": {
      "state": "tokyo",
      "city": "shinjuku"
    }
  }
]
```

### CSV化

`@csv`を利用することで、jsonをcsvに変換することができます。
入力するjsonは配列である必要があります。
ユーザ情報をcsvとして取得してみます。

```bash
$ cat users.json | jq -r '.[] | [.name, .age, .address.state + " " + .address.city]| @csv'
"Tanaka",25,"tokyo shinjuku"
"Suzuki",30,"chiba funabashi"
```

## 最後に
今回はjqの使い方を学びました。エンジニアである以上、JSONとは切っても切り離せない関係です。
そんなJSONを効率よく扱う方法を学べたことは、自分にとって大きな財産になったと思います。
以上、閲覧していただきありがとうございました！！

皆さんのお気に入りの使い方がありましたら、ぜひコメントしていってください！