23
20

More than 5 years have passed since last update.

jq で連続する JSON を特定のキーでソートする

Last updated at Posted at 2015-08-05

やりたいこと

jq で以下のような JSON を入力として、

{"id":5}
{"id":2}
{"id":1}
{"id":4}
{"id":3}

特定のキーの値 (この場合は id) でソートして出力したい。

{"id":1}
{"id":2}
{"id":3}
{"id":4}
{"id":5}

結論

$ jq 'sort_by(.id) | .[]' --slurp input.json

以下、やっていることの詳細を説明します。

sort_by

ソートについて jq のマニュアルを調べると、 sort_by という関数が見つかります。

sort, sort_by(path_expression)

しかしこれは、今回やりたいことと微妙に異なるものです。
sortsort_byArray を入出力にするもので、たとえば以下のようにしてもエラーになります。

$ jq 'sort_by(.id)' input.json
jq: error: Cannot index number with string
jq: error: object and array cannot be sorted, as they are not both arrays
...

jq では連続する JSON をストリームのように受け取れますが、これはあくまでストリームであって Array ではありません。
とはいえ、これを Array に変換することができれば sort_by が使えそうです。

--slurp

コマンドラインオプションの --slurp がまさに連続する JSON を Array にするためのものです。

つまり、通常以下のようになる入力であれば、

$ jq '.' input.json
{"id":5}
{"id":2}
{"id":1}
{"id":4}
{"id":3}

--slurp をつけると以下のようになります。

$ jq '.' --slurp input.json
[
  {"id":5},
  {"id":2},
  {"id":1},
  {"id":4},
  {"id":3}
]

※一部インデントを調整しています。

というわけで連続する JSON を Array にすることができたので、あとはこれを sort_by すればよいことになります。
出力が Array にくるまれてほしくないのであれば、さらに | .[] にパイプして Array の皮をむいて完成です。

おまけ: jr ならもっと直感的にできるよ

拙作の jr であれば、より直感的に書くことが可能です。

$ jr 'sort_by(&:id)' input.json

--slurp オプション無しでできました。
(そもそも --slurp オプション自体ないんですが)

jr では連続する JSON を Enumerable として受け取るので、Enumerable が持つメソッドなら何でも適用することができます。
普段から Ruby を書いているかたであればオススメです。

23
20
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
23
20