[jq] 複数のjsonデータを変数に格納して便利に使う方法

2019年4月15日

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

jqコマンドをかなり便利に使いこなせるようになってきました。 もはやSQLを使うことなどありえないぐらいjsonデータだけで何でもシステム構築できるようになってきました。 SQLの便利ポイントって、データベースの設定だけ行って入力、出力規則を守っていれば、安心して管理を行ってくれる点や、ツール毎に便利機能などもありますが、SQLを使っているけどSELECT地獄から逃れられないエンジニアも多いようです。 もちろん、今現在行っている開発ルールとしてSQLにデータを格納するってなっている現場がほとんどなので、自分の一存ではデータ形式など決められない人も多いかもしれませんが、基本データはSQLだけど、システムでほんのちょっとだけ使うデータでSQLにtableを作ってまで登録する必要がないデータをテキストデータで管理する場合など、意外と少なくないようです。 SQL以外のデータを扱わなければならないエンジニアって意外と多いんですが、SQL以外はよく分からないというエンジニアもまた多い感覚がありますね。 みんなSQL大好きなんですね。 jsonでファイル操作した方がよっぽど開発スピードも早いし、データ管理も楽だし、サーバー負荷も少ないのに・・・管理運用コストは圧倒的に違いますけどね・・・ そんなjsonデータが複数存在していて、それらをそれぞれ変数に格納してデータ操作を行いたい場合に、jqコマンドで簡単に行えてしまいます。

複数データの読み込み方法

サンプルデータとして下記の2ファイルを用意します。 {"id":"1","name":"aaa"} {"id":"2","name1":"bbb"} {"id":"3","name1":"ccc"} {"id":"4","name1":"ddd"} {"id":"5","name1":"eee"} {"id":"1","name":"AAA"} {"id":"2","name2":"BBB"} {"id":"3","name2":"CCC"} {"id":"4","name2":"DDD"} {"id":"5","name2":"EEE"} $ jq -n --slurpfile a a.json --slurpfile b b.json '{a:$a,b:$b}' # Responce { "a": [ { "id": "1", "name1": "aaa" }, { "id": "2", "name1": "bbb" }, { "id": "3", "name1": "ccc" }, { "id": "4", "name1": "ddd" }, { "id": "5", "name1": "eee" } ], "b": [ { "id": "1", "name2": "AAA" }, { "id": "2", "name2": "BBB" }, { "id": "3", "name2": "CCC" }, { "id": "4", "name2": "DDD" }, { "id": "5", "name2": "EEE" } ] } 「a」と「b」という変数にファイルのデータを取り込んで、最後に、「$a」、「$b」という風に呼び出すことが可能になります。 ここでの注意点は、jqコマンドに"-n"オプションを追加しないと、ハングアップしてしまいます。 このオプションは、通常のjqコマンドは、ファイルまたは、パイプで繋いだjsonデータを参照しないと行けないため、上記のコマンドで-nオプションを付けない状態では、読み込み待ちで待機状態に陥ってしまいます。 それを、読み込みを一旦"null"で対応してくれる便利機能という事です。 このモードは本来は、jqコマンドを使って、計算などを行なうためのオプションのようですが、複数ファイル読み込みで便利に使えてしまいます。

ファイル読み込みにjqを指定できる

単純にjsonファイルを読み込むというのはシンプルでいいのですが、読み込むjsonデータをさらに"jq"コマンドでデータ整形して取得することも可能です。 jq -n --slurpfile a <(jq 'select(.id=="1")' a.json) --slurpfile b <(jq 'select(.id=="1")' b.json) '{a:$a,b:$b}' # Responce { "a": [ { "id": "1", "name1": "aaa" } ], "b": [ { "id": "1", "name2": "AAA" } ] } slurpfileオプションのファイル指定をする箇所でjqが指定できると、読み込み時点で不要な情報を削除したり、整形をし直したりできるので、便利ですね。

他サイトでも紹介されているマージ処理の方法

上記のサンプルでは、aとbという階層を作って、そこにそれぞれのデータをぶち込んでいるだけなのですが、これをマージした状態にするサンプルがネットで紹介されています。 ただ、海外サイトも含めて、ゴールに辿り着くのに手間がかかったので、こちらでまとめておきます。 以下のサンプルソースで結合が可能になります。 ただし、今回はマージ処理を行う関数ファイルを事前に作ってからコマンドを実行します。 def hashJoin(a; b; field): # hash phase: (reduce a[] as $o ({}; . + { ($o | field): $o } )) as $h1 | (reduce b[] as $o ({}; . + { ($o | field): $o } )) as $h2 # join phase: | reduce ($h1|keys[]) as $key ([]; if $h2|has($key) then . + [ $h1[$key] + $h2[$key] ] else . end) ; hashJoin( $a; $b; .id)[] jq -n --slurpfile a a.json --slurpfile b b.json -f join.jq # Responce { "id": "1", "name1": "aaa", "name2": "AAA" } { "id": "2", "name1": "bbb", "name2": "BBB" } { "id": "3", "name1": "ccc", "name2": "CCC" } { "id": "4", "name1": "ddd", "name2": "DDD" } { "id": "5", "name1": "eee", "name2": "EEE" } "hashJoin"という関数を実行して、内部でリレーションkeyなどを判定しているのが見て分かります。 関数の便利な使い方などは、また別の機械に行ないたいと思いますが、jsonデータを複数管理して、取得データの整形などが便利に行える感覚がわかってもらえると、この記事を書いた甲斐があります。 この記事を書いて、改めてjqコマンドの奥深さを体感しました。

このブログを検索

ごあいさつ

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