[jq] selectで存在しないレコードを選択する方法

2019年3月25日

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

t f B! P L
SQLデータベースに非効率を感じてテキストデータベースを使いこなしている僕ですが、jqコマンドが便利すぎてSELECTコマンドよりも使えるモジュールとして"my favorite"と化している状態です。 もはや、SQLを使わないWEBサービスなんて有り得ないというライブラリ依存エンジニアからすると変態クラスの思考なのですが、実はこの思考になれてしまうと、開発スピードアップ、サーバー環境簡素化、セキュリティ管理効率化・・・などなどメリットが多く、技術力の向上も半端ありません。 そんな便利なjqコマンドとはなんぞや???という方は過去記事(下記リンク)を参考にしてみてくださいね。 [jqコマンド] ログデータを集計する時は"group_by"がめっちゃええ感じ

運用によくあるデータ構成変更

データベースを運用していると、機能追加や途中から加わってくる情報をすでに構築済みのデータ群に反映しなければ行けない時があります。 SQLの場合は、テーブル管理で、カラム情報を追加すれば、いいのですが、テキストデータベースは、過去データの変更はしないほうが運用トラブルが発生しづらいという事を理解していると、カラム情報の存在可否という判定が必要になります。 少し分かりづらいので、サンプルデータを使って説明します。 売上情報を下記のようなjsonデータで運用している状態を現在とします。 {"date":"20190201","name":"田中","sales":10000} {"date":"20190202","name":"鈴木","sales":15000} {"date":"20190203","name":"吉田","sales":20000} {"date":"20190204","name":"斉藤","sales":25000} {"date":"20190205","name":"佐藤","sales":30000} 20,000円以上の売上データを取得したい場合には、以下のようにします。 jq --slurp --compact-output '.[] | select(.sales >= 20000) | {name:.name , sales:.sales}' data.json {"name":"吉田","sales":20000} {"name":"斉藤","sales":25000} {"name":"佐藤","sales":30000} これに、販売した商品情報を追加したいとする場合、これまでのデータにもその属性を入れたい場合は過去データを上書きして、以下のような状態にします。 {"date":"20190201","name":"田中","sales":10000,"product":"toy"} {"date":"20190202","name":"鈴木","sales":15000,"product":"gadget"} {"date":"20190203","name":"吉田","sales":20000,"product":"wear"} {"date":"20190204","name":"斉藤","sales":25000,"product":"food"} {"date":"20190205","name":"佐藤","sales":30000,"product":"toy"} さらに、商品(product)"toy"の2万円以上のデータを取得する場合は以下のように書きます。 jq --slurp --compact-output '.[] | select(.sales >= 20000) | select(.product=="toy") | {name:.name , sales:.sales}' data2.json {"name":"佐藤","sales":30000} ただし、実運用において、サービスをメンテナンス状態にしてデータの書き換えをすることがデメリットの場合、これまでのデータは変更せずに、これから追記するデータのみに登録する状態でもいいという運用は、結構多発します。 確かに過去データを上書きするというリスクがあるかもしれない状態を回避できてメリットのように思うかもしれませんが、出来上がったデータは以下のようになります。 {"date":"20190201","name":"田中","sales":10000} {"date":"20190202","name":"鈴木","sales":15000} {"date":"20190203","name":"吉田","sales":20000} {"date":"20190204","name":"斉藤","sales":25000} {"date":"20190205","name":"佐藤","sales":30000} {"date":"20190206","name":"田中","sales":10000,"product":"toy"} {"date":"20190207","name":"鈴木","sales":15000,"product":"gadget"} {"date":"20190208","name":"吉田","sales":20000,"product":"wear"} {"date":"20190209","name":"斉藤","sales":25000,"product":"food"} {"date":"20190210","name":"佐藤","sales":30000,"product":"toy"} ここで、2万円以上の売上で且つ商品"toy"のもの、または過去データ(product属性の無いもの)を選択する場合、selectはどういう風に書けばいいのかと言うと、以下のようにします。 jq --slurp --compact-output '.[] | select(.sales >= 20000) | select(.product=="toy",.product==null) | {name:.name , sales:.sales}' data3.json {"name":"吉田","sales":20000} {"name":"斉藤","sales":25000} {"name":"佐藤","sales":30000} {"name":"佐藤","sales":30000} 存在可否は"null"で行うんですね。 注意しなければならないポイントとしては、{product:null}にもマッチしてしまうので、nullをシステムで使っている場合は、属性可否と混ざってしまわないようにしなければいけませんが、select判定でのコンフリクトは概ね問題ないかと思われます。 これでますますjqコマンドを便利に使えるイメージが湧いてきましたね。

人気の投稿

このブログを検索

ごあいさつ

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

ブログ アーカイブ