[jqコマンド] 使い方サンプル「日付のユニーク値(最新採用)で論理削除フラグを除外して、整形したjsonデータを書き出す」

2019年1月3日

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

テキストデータをjsonで統一すると、jqコマンドが便利すぎて極めたくなってきました。 jqコマンドって何かと言うと、jsonデータが記述されたテキストファイルをターミナルコマンドでparseしてデータ検索して取得したり、整形したりできる非常に便利で強力なデータアクセスコマンドです。 以前にブログでも書いたので、jqコマンドについては、以下を参照してください。 JSONファイルをコマンドで扱える「jq」を学習してみる #1「初期設定」 そして今回は、なるべくawkやパイプ繋ぎのshellを使わない様にjqの一発コマンドで行える様にする為に、対応したjqコマンドのサンプルを備忘録として書き溜めておきます。

基本jsonデータ構造

テキストファイルの行毎にjsonフォーマットを格納しているログ形式のjsonデータファイルです。 サンプルは以下のような感じ。 {"column-1" : 1 , "column-2" : 2 , "column-3" : 3} {"column-1" : 4 , "column-2" : 5 , "column-3" : 6} {"column-1" : 7 , "column-2" : 8 , "column-3" : 9} {"column-1" : 10 , "column-2" : 11 , "column-3" : 12} {"column-1" : 13 , "column-2" : 14 , "column-3" : 15} 各行毎に、同じkey(カラム)名になっていますが、データ統制としては、同じである事が望ましいですが、jqコマンドを使う場合には、必ず同じになっていないといけないわけではありません。 存在するkey値を元に集計できるのは、非常に便利ですね。

元データ

ログデータや、日付を元にしたデータ登録でもっともスタンダードなやり方なので、これをベースにコマンドを書き換えていくとやりやすいと思います。 {"date":20180904,"code":"3909","memo":"test-2"} {"date":20181205,"code":"3909","memo":"test"} {"date":20180801,"code":"3909","memo":"aaa-aaa"} {"date":20180802,"code":"3909","memo":"bbb-bbb"} {"date":20180808,"code":"3909","memo":"ccc-ccc"} {"date":20180809,"code":"3909","memo":"eee-eee"} {"date":20180806,"code":"3909","memo":"fff-fff"} {"date":20180807,"code":"3909","memo":"ggg-ggg"} {"date":20180805,"code":"3909","memo":"ddd-ddd"} {"date":20181202,"code":"3909","memo":"aaa"} {"date":20181020,"code":"3909","memo":"bbb"} {"date":20181001,"code":"3908","memo":"test"} {"date":20181001,"flg":1,"code":"3908"} {"flg":1,"date":20180802,"code":"3909","memo":"bbb-bbb"}

コマンド

jq -s '[sort_by(.date) | reverse | unique_by(.date) | reverse[] | select(.flg!=1) | {type:"memo" , date:.date , memo:.memo} ]' data_1.json

解説

出力にtypeをつけているのは、このデータを利用するシステム用に設置しています。 出力の際にこのように任意フラグを設置することも可能なので、かなり重宝できまね。 ここでは、jqコマンドの基本的な記述ではなく、コマンド内の核部分を解説します。 [sort_by(.date) | reverse | unique_by(.date) | reverse[] | select(.flg!=1) | {type:"memo" , date:.date , memo:.memo} ] この部分ですね。 まず、最初に.dateで"sort"して、それを"reverse"しているのは、そのあとのunique_byで、先頭を残して削られてしまうので、追記型のデータでは、下に書かれているものが有効になります。 そのための"reverse"です。 そして、"unique_by"で.dateとして日付を最新情報を残して絞り込みます。 この際になぜかデータが"sort"処理されてしまうので、最新順での出力にする為に、すぐ後で再度"reverse"処理をしています。 ちなみに、このreverseに"[]"をつけているのは、その後のselectなどの操作は、配列内で行う処理になるので、データの切り替え処理だと思ってください。 最新順でなく、古い順の表示をする場合は、この"reverse[]"を無くして、代わりにデータ切り替えとして、"unique_by(.date)"を"unique_by(.date)[]"として切り替えてください。 その後"select"で.flgが1でないものをピックアップ(1を除外)することで論理削除フラグを排除しています。 次に、出力するjsonデータフォーマットを任意に整形しています。{key:value}で、それぞれ値をはめ込む事ができるので、都合のいい形式での出力ができます。 ちなみに、key値に元jsonのvalueを当て込むこともできるので、この辺はデータ設計をきちんと行なった上で実行してください。 そして、最後に一番重要なのが、これらのjsonデータを出力する時に、ログデータの形式のような形では、レコード単位での複数json形式になってしまうので、一括したjson形式にするために、全ての操作を"[**]"で囲ってあげます。 こうすることで、内容した複数のデータを配列にして出力する事が可能になります。 途中で行なったデータ切り替えの逆の操作になります。

結果

[ { "type": "memo", "date": 20181205, "memo": "test" }, { "type": "memo", "date": 20181202, "memo": "aaa" }, { "type": "memo", "date": 20181020, "memo": "bbb" }, { "type": "memo", "date": 20180904, "memo": "test-2" }, { "type": "memo", "date": 20180809, "memo": "eee-eee" }, { "type": "memo", "date": 20180808, "memo": "ccc-ccc" }, { "type": "memo", "date": 20180807, "memo": "ggg-ggg" }, { "type": "memo", "date": 20180806, "memo": "fff-fff" }, { "type": "memo", "date": 20180805, "memo": "ddd-ddd" }, { "type": "memo", "date": 20180801, "memo": "aaa-aaa" } ] スピードもかなり早く、簡易なシステムで使うことでわざわざSQLを介す必要もなく、データコントロールができるようになるので、非常に便利です。

このブログを検索

ごあいさつ

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