jq 1.7の新機能ーpick

[JSON](https://datatracker.ietf.org/doc/html/rfc8259)処理のコマンドラインツールである[jq](https://stedolan.github.io/jq/)が、5年ぶりにアップデートしました。現在の最新は1.7.1（2023年12月リリース）です。1.6からいろいろと改定や新機能の追加があって、ますます楽しくなっています。

全容は[Github上のリリースノート](https://github.com/jqlang/jq/releases)を見ていただくとして、今日は新機能の`pick`を試してみます。この関数はSQLの射影を実装したものです（`SELECT シリアルコード FROM データベース`のようにテーブルの特定のコラムだけを抽出する操作）。

オブジェクトを対象にした例題には、次のGithubのREST APIを使います。

```bash
$ curl -s https://api.github.com/users/octocat
{
  "login": "octocat",
  "id": 583231,
  ︙
  "created_at": "2011-01-25T18:44:36Z",
  "updated_at": "2024-01-22T12:23:59Z"
}
```


### これまでは

オブジェクトから特定のプロパティ値だけを抜き出すのは簡単です。たとえば、上記から`login`プロパティ値だけを抜き出すならこうです。

```bash
$ curl -s https://api.github.com/users/octocat | jq '.login'
"octocat"
```

しかし、プロパティ名も含めてオブジェクトとして抽出したいとなると、`with_entries`というやや面妖な関数を`select`と組み合わせて使わなければなりません。

```bash
$ curl -s https://api.github.com/users/octocat | jq 'with_entries(select(.key == "login"))'
{
  "login": "octocat"
}
```

プロパティ1つくらいならたいしたことないですが、複数を選択するとなると、`select`が混雑して読みづらくなります。


### これからは

`pick`は引数に指定されたパス表記（`.login`や`.[1]`など）のオブジェクトをそのまま抽出する関数です。上記は次のようにシンプルに書けます。

```bash
$ curl -s https://api.github.com/users/octocat | jq 'pick(.login)'
{
  "login": "octocat"
}
```

当然、v1.7以前では動作しません。

```bash
$ jq-1.6 --version
jq-1.6

$ curl -s https://api.github.com/users/octocat | jq-1.6 'pick(.login)'
jq: error: pick/1 is not defined at <top-level>, line 1:
pick(.login)
jq: 1 compile error
```


### 配列だと

`pick`は配列でも使えますが、やや癖があります。5要素からなる配列から1番目と3番目の要素を抽出しようとします（要素番号は0からカウント）。

```bash
$ echo '[0, 1, 2, 3, 4]' | jq 'pick(.[1,3])'
[
  null,
  1,
  null,
  3
]
```

どうやら、0番目から指定の要素番号の最大のところまで`null`で埋まった配列を用意し、抽出したものだけはその位置でその値で埋めるようです。ここでは3番目が最大の要素番号なので4つの`null`で埋まった配列ができ、そこに1番目と3番目だけはもともとの値で埋まります。

おそらく、この関数は要素位置を温存したいときに効力を発揮するようです。`[1, 3]`のように抽出した要素だけに縮退させたいのなら、`null`を別途省きます。


```bash
$ echo '[0, 1, 2, 3, 4]' | jq 'pick(.[1,3]) | map(select(. != null))'
[
  1,
  3
]
```

でも、そこまでするくらいなら、角括弧が連続して読みにくいものの、これまでどおり、抽出結果を`[]`でくくって配列化したほうが早いでしょう。

```bash
$ echo '[0, 1, 2, 3, 4]' | jq '[ .[1, 3] ]'
[
  1,
  3
]
```


### おわりに

他にも、数値の精度が上がるなど、細かいところで性能向上も図られています。まだ1.6をお使いなら、これを機会に1.7にアップグレードしましょう。


### 参考

- [./jq](https://stedolan.github.io/jq/) ... `jq`のオフィシャルサイトです（英文）。
- [Github jqland/jq Releases](https://github.com/jqlang/jq/releases) ... `jq`のリリースノートです（英文）。
- 『[jqハンドブック](http://www.cutt.co.jp/book/978-4-87783-491-3.html)』（2021）... オブジェクトのキーと値を同時に操作する`with_entries`の用法は、この本の8.2節で紹介しています。配列化の`[]`は3.1節、数値精度の問題は5.8節です。ご購入はこちらから【[出版社](http://www.cutt.co.jp/book/978-4-87783-491-3.html) | [honto](https://honto.jp/netstore/pd-book_31037910.html) | [amazon.co.jp](https://www.amazon.co.jp/jq/dp/4877834915) | [ヨドバシカメラ](https://www.yodobashi.com/product/100000009003450000/)】。
- 「[jqのむだづかい](https://qiita.com/stoyosawa)」 ... `jq`ではまずやろうとは思わない処理の探求記録です。完成版は他の（通常機能な）レシピとともに『[jqクックブック](https://www.cutt.co.jp/book/978-4-87783-508-8.html)』（2023）に掲載しました。ご購入はこちらから【[出版社](https://www.cutt.co.jp/book/978-4-87783-508-8.html) | [honto](https://honto.jp/netstore/pd-book_32427461.html) | [amazon.co.jp](https://www.amazon.co.jp/dp/4877835083) | [ヨドバシカメラ](https://www.yodobashi.com/product/100000009003710680/)】。

<img src="http://www.cutt.co.jp/book/images/978-4-87783-491-3.png" width="200" alt="表紙"></img>　<img src="https://www.cutt.co.jp/book/images/978-4-87783-508-8.png" width="200" alt="表紙"></img>