jqコマンドでは、JSONファイルでの集計処理(キーの数を数えたり、合計や平均、最大値や最小値を出したり)をすることが出来る。
なお、今回は以下のようなJSONファイルをサンプルに進めていく。

sample1.json

json
[ { "id": "0001", "name": "test001", "value": 112, "group1": { "subg01": [ { "id": "1001", "type": "type001" }, { "id": "1004", "type": "type002" } ] }, "group2": [ { "id": "5001", "type": "None" }, { "id": "5003", "type": "type053" }, { "id": "5004", "type": "type054" } ] }, { "id": "0002", "name": "test002", "value": 954, "group1": { "subg01": [ { "id": "1021", "type": "type101" }, { "id": "1054", "type": "type052" } ] }, "group2": [ { "id": "5001", "type": "None" }, { "id": "5004", "type": "type054" } ] } ]

sample3.json

json
[ { "id": 1, "value": 1243, "type": "A" }, { "id": 2, "value": 24365, "type": "B" }, { "id": 3, "value": 201, "type": "B" }, { "id": 4, "value": 5465, "type": "C" }, { "id": 5, "value": 24, "type": "A" }, { "id": 6, "value": 54750, "type": "B" }, { "id": 7, "value": 3547, "type": "B" } ]

1.キーの数を求める

'length'を用いる事で、配列内のキー数の数をカウントすることが出来る。

shell
[root@BS-PUB-CENT7-02 ~]# # 指定した配列内のキー数を取得する [root@BS-PUB-CENT7-02 ~]# jq -c '.[] | select(.id == "0002") | .group1.subg01[1]' /tmp/sample1.json {"id":"1054","type":"type052"} [root@BS-PUB-CENT7-02 ~]# jq -c '.[] | select(.id == "0002") | .group1.subg01[1] | length' /tmp/sample1.json 2 [root@BS-PUB-CENT7-02 ~]# [root@BS-PUB-CENT7-02 ~]# # 配列でないキーの数をカウントしたい場合は、length前の抽出文を[]で囲って配列として扱わせる [root@BS-PUB-CENT7-02 ~]# jq -c '.[] | select((.value >= 1000 ) and (.type == "B") | not) | .id' /tmp/sample3.json 1 3 4 5 [root@BS-PUB-CENT7-02 ~]# jq -c '[.[] | select((.value >= 1000 ) and (.type == "B") | not) | .id]' /tmp/sample3.json [1,3,4,5] [root@BS-PUB-CENT7-02 ~]# jq -c '[.[] | select((.value >= 1000 ) and (.type == "B") | not) | .id] | length' /tmp/sample3.json 4

この時、group_byを利用することで要素ごとの数を求める事も可能だ。

shell
[root@BS-PUB-CENT7-02 ~]# # 「type」のそれぞれの数を求めたいとする [root@BS-PUB-CENT7-02 ~]# jq -c '.[] | .type' /tmp/sample3.json "A" "B" "B" "C" "A" "B" "B" [root@BS-PUB-CENT7-02 ~]# # 一度配列にしてやる必要がある [root@BS-PUB-CENT7-02 ~]# jq -c '[.[] | .type]' /tmp/sample3.json ["A","B","B","C","A","B","B"] [root@BS-PUB-CENT7-02 ~]# # 「group_by」で値ごとに配列を分ける [root@BS-PUB-CENT7-02 ~]# jq -c '[.[] | .type] | group_by(.)' /tmp/sample3.json [["A","A"],["B","B","B","B"],["C"]] [root@BS-PUB-CENT7-02 ~]# # mapで配列ごとにカウントする [root@BS-PUB-CENT7-02 ~]# jq -c '[.[] | .type] | group_by(.) | map({(.[0]): length})' /tmp/sample3.json [{"A":2},{"B":4},{"C":1}] [root@BS-PUB-CENT7-02 ~]# jq -c '[.[] | .type] | group_by(.) | map({(.[0]): length}) | add' /tmp/sample3.json {"A":2,"B":4,"C":1}

2.キーの値の合計を求める

'add'で、配列内の値を合計することが出来る。

shell
[root@BS-PUB-CENT7-02 ~]# # 集計したい条件を指定 [root@BS-PUB-CENT7-02 ~]# jq -c '.[] | select((.value >= 1000 ) and (.type == "B")) | .value' /tmp/sample3.json 24365 54750 3547 [root@BS-PUB-CENT7-02 ~]# # 1回配列にする [root@BS-PUB-CENT7-02 ~]# jq -c '[.[] | select((.value >= 1000 ) and (.type == "B")) | .value]' /tmp/sample3.json [24365,54750,3547] [root@BS-PUB-CENT7-02 ~]# # 合計値を取得 [root@BS-PUB-CENT7-02 ~]# jq -c '[.[] | select((.value >= 1000 ) and (.type == "B")) | .value] | add' /tmp/sample3.json 82662

グループごとに合計を算出することもできる。
以下の例では、「type」の値に応じて合計値を算出する。

shell
[root@BS-PUB-CENT7-02 ~]# # 最初に、group_byでtypeごとに配列を分ける [root@BS-PUB-CENT7-02 ~]# jq -c 'group_by(.type)' /tmp/sample3.json [[{"id":1,"value":1243,"type":"A"},{"id":5,"value":24,"type":"A"}],[{"id":2,"value":24365,"type":"B"},{"id":3,"value":201,"type":"B"},{"id":6,"value":54750,"type":"B"},{"id":7,"value":3547,"type":"B"}],[{"id":4,"value":5465,"type":"C"}]] [root@BS-PUB-CENT7-02 ~]# # mapで必要な情報だけを抽出する(この段階だと配列の数がvalueの数の2乗になる) ``` [root@BS-PUB-CENT7-02 ~]# jq -c 'group_by(.type) | map( {(.[].type): (.[].value)} )' /tmp/sample3.json \[{"A":1243},{"A":24},{"A":1243},{"A":24},{"B":24365},{"B":201},{"B":54750},{"B":3547},{"B":24365},{"B":201},{"B":54750},{"B":3547},{"B":24365},{"B":201},{"B":54750},{"B":3547},{"B":24365},{"B":201},{"B":54750},{"B":3547},{"C":5465}\] \[root@BS-PUB-CENT7-02 ~\]# # reduceで認識した順に足す処理を追記する(配列の数だけ重複した集計が出力される) [root@BS-PUB-CENT7-02 ~]# jq -c 'group_by(.type)| map({(.[].type): (reduce .[].value as $value (0; . + $value))})' /tmp/sample3.json \[{"A":1267},{"A":1267},{"B":82863},{"B":82863},{"B":82863},{"B":82863},{"C":5465}\] \[root@BS-PUB-CENT7-02 ~\]# # ユニークな値のみを抽出する [root@BS-PUB-CENT7-02 ~]# jq -c 'group_by(.type)| map({(.[].type): (reduce .[].value as $value (0; . + $value))}) | unique' /tmp/sample3.json \[{"A":1267},{"B":82863},{"C":5465}\] \[root@BS-PUB-CENT7-02 ~\]# jq -c 'group_by(.type)| map({(.[].type): (reduce .[].value as $value (0; . + $value))}) | unique | add' /tmp/sample3.json {"A":1267,"B":82863,"C":5465} [root@BS-PUB-CENT7-02 ~]# [root@BS-PUB-CENT7-02 ~]# # 配列に突っ込む方式もある(こっちの方がキレイ) [root@BS-PUB-CENT7-02 ~]# jq -c 'group_by(.type)| map({(.[].type): ([.[].value]|add)}) | unique' /tmp/sample3.json [{"A":1267},{"B":82863},{"C":5465}] # 3.平均を求める 上の合計・キーの数を求めるやり方を利用することで、平均を求める事が出来る。 ```shell [root@BS-PUB-CENT7-02 ~]# # 合計(add),個数(length)を求める [root@BS-PUB-CENT7-02 ~]# jq '[.[] | select((.value >= 1000 ) and (.type == "B")) | .value] | add,length' /tmp/sample3.json 82662 3 [root@BS-PUB-CENT7-02 ~]# [root@BS-PUB-CENT7-02 ~]# # 合計(add)/個数(length)で平均を求める [root@BS-PUB-CENT7-02 ~]# jq '[.[] | select((.value >= 1000 ) and (.type == "B")) | .value] | add/length' /tmp/sample3.json 27554</pre> もちろん、グループごとの平均値を求める事も可能だ。 ```shell [root@BS-PUB-CENT7-02 ~]# jq -c 'group_by(.type)| map({(.[].type): (reduce .[].value as $value (0; . + $value)/length)}) | unique' /tmp/sample3.json [{"A":633.5},{"B":20715.75},{"C":5465}] [root@BS-PUB-CENT7-02 ~]# jq -c 'group_by(.type)| map({(.[].type): ([.[].value]|add/length)}) | unique' /tmp/sample3.json [{"A":633.5},{"B":20715.75},{"C":5465}]

4.最大値・最小値を求める

最大値を求める場合は、「max」「max_by」を、最小値を求める場合は「min」「min_by」を用いる。

shell
[root@BS-PUB-CENT7-02 ~]# # 配列内の最大・最小値を求める [root@BS-PUB-CENT7-02 ~]# jq -c '[.[] | .value]' /tmp/sample3.json [1243,24365,201,5465,24,54750,3547] [root@BS-PUB-CENT7-02 ~]# jq -c '[.[] | .value] | max' /tmp/sample3.json 54750 [root@BS-PUB-CENT7-02 ~]# jq -c '[.[] | .value] | min' /tmp/sample3.json 24 [root@BS-PUB-CENT7-02 ~]# [root@BS-PUB-CENT7-02 ~]# # 最大・最小値を持つ配列を抽出する [root@BS-PUB-CENT7-02 ~]# jq -c 'max_by(.value)' /tmp/sample3.json {"id":6,"value":54750,"type":"B"} [root@BS-PUB-CENT7-02 ~]# jq -c 'min_by(.value)' /tmp/sample3.json {"id":5,"value":24,"type":"A"}

グループごとでの最大値・最小値を求める

shell
[root@BS-PUB-CENT7-02 ~]# jq -c 'group_by(.type)| map({(.[].type): ([.[].value]|max)}) | unique' /tmp/sample3.json [{"A":1243},{"B":54750},{"C":5465}] [root@BS-PUB-CENT7-02 ~]# jq -c 'group_by(.type)| map({(.[].type): ([.[].value]|min)}) | unique' /tmp/sample3.json [{"A":24},{"B":201},{"C":5465}]