[jq] reduceを極めてデータ・フォーマットを自由自在に変換

2019年4月12日

jq テクノロジー プログラミング

jqコマンドをjsonフォーマットのデータ取得ツールだと侮ってはいけません。 確かに、改行など整形されていないjsonデータって、見た目には分かりづらいので、運用管理をする際などには、人の目でわかりやすい整形を行なうことで、作業が捗るためにjqコマンドを使うようなケースは簡単に行なえます。 {"id":"10","data":"abc"}{"id":"20","data":"xyz"}{"id":"30","data":"qwe"}{"id":"40","data":"wsx"}{"id":"50","data":"zxc"} こういう、ごちゃっとしたデータを、jqコマンドを通せば、以下のようになります。 $ jq '.' test.json { "id": "10", "data": "abc" } { "id": "20", "data": "xyz" } { "id": "30", "data": "qwe" } { "id": "40", "data": "wsx" } { "id": "50", "data": "zxc" } 見食べは非常にわかりやすいのですが、実際のデータは、改行コードやタブコードなど不要な文字列が入るため、データ蓄積する際には無駄使いになるので、こうした簡単な処理で見た目が分かりやすくなるのであれば、その仕様で問題ありません。 ここで考えたいのは、jqコマンドはこうした単なるデータ表示ツールではなく、データ整形に関しても非常に高機能な使い方ができるツールで有るため、使いこなせばプログラムでいちいちパースして変換して整形するような作業がjqコマンド一発で行えるようになります。 その代表的な機能として「reduce」機能を今回は紹介します。

key-valueの形式に変換

上記test.jsonを使って、idの値をkey、dataの値をvalueにして、hashデータに変換してみたいと思います。 ちなみに、以前にも、「from_entries」を使った方法で書いたのですが、今回のやり方の方が汎用性が高いと思うので、別のやり方として紹介します。 [jq] アウトプットをkey-value形式の連想配列で出力する方法 reduce .[] as $item({}; . + {($item.id) : $item.data} ) { "10": "abc", "20": "xyz", "30": "qwe", "40": "wsx", "50": "zxc" } 少し分かりにくいので解説すると、reduceは以下のような公文になっています。 reduce "元データ" as "配列の各データの格納変数" ("出力形式"; . + "出力フォーマット")

元データ

今回の元データは配列なので、".[]"を当てはめています。

配列の各データの格納変数

$itemという変数を作って、配列の要素データが格納される、foreachのような動きになります。

出力形式

[]か{}で記述するだけでいいでしょう。 マニュアルには0などの数字が書かれていますが、これは、配列内の数値を集計して合計値を算出する場合などにも使うことが可能です。

出力フォーマット

ここが一番のミソなのですが、「. + "出力フォーマット"」という風に、データを追加していく様な感覚で出力フォーマットは通常のjqコマンドでアウトプットするフォーマットと同じ様な書き方で大丈夫です。 ちなみに、数値計算する時は、ここに変数の値を足しこんでいくだけでいいので覚えておくと便利に使えます。

注意ポイント

出力フォーマットのkeyの部分に変数を当てはめる時は、()カッコでくくってあげないとエラーになります。

データ一覧を配列で出力

jq --slurp 'reduce .[] as $item([]; . + [$item.data] )' test.json [ "abc", "xyz", "qwe", "wsx", "zxc" ] 要領は上記と同じですが、reduceを使ってデータを別フォーマットで出力するわかりやすい例です。 同様にkey一覧の抜き出しなども自分でやってみるとかなり理解できるようになりますよ。

変換結果を変数に格納

jq --slurp '(reduce .[] as $item([]; . + [$item.data] )) as $d1 | (reduce .[] as $item([]; . + [$item.id] )) as $d2 | $d1 + $d2' [ "abc", "xyz", "qwe", "wsx", "zxc", "10", "20", "30", "40", "50" ] jqコマンドでは、変換したデータを更に変数に格納することが可能です。 上記は、idとdataをそれぞれ変数に格納して、最後にその変数を繋げているサンプルです。 jqでの一次元配列の連結は"+"プラスで簡単にできるので、非常に楽にこういうデータが作成できますね。 こういう技を覚えると、ピンとくるエンジニアの方も多いかもしれませんが、jqコマンドだけで、複数のjsonファイルデータのリレーショナル・データベース処理が行えるようになるという事ですね。 実際にやると、大変になるので、リレーショナルのやり方は後日ブログにて掲載したいと思います。

このブログを検索

ごあいさつ

このWebサイトは、独自思考で我が道を行くユゲタの少し尖った思考のTechブログです。 毎日興味がどんどん切り替わるので、テーマはマルチになっています。 もしかしたらアイデアに困っている人の助けになるかもしれません。