jqで複数のjsonファイルから特定のデータを抽出してみた
はじめに
こんにちはスペースマーケットでエンジニアをしているderaです。
先日、集計の中間データとして出力されるjsonの解析する事がありました。ファイルサイズが数百MBありエディターで開くことが難しかったが、jqを使うことで内容の確認をする事ができました。今回はその内容を備忘録として残しておきます。
環境
- macOS Ventura 13.5.2
- jq 1.7
どのような事をしたのか
まずどのような事をしたのかですが、以下のようなデータがあったとします。
// data1.json
{
"type": "タイプ1",
"users": [
{
"id": 1,
"values": [
{
"id": 1,
"value": 100
}
]
},
{
"id": 2,
"values": [
{
"id": 2,
"value": 200
}
]
}
]
}
// data2.json
{
"type": "タイプ2",
"users": [
{
"id": 2,
"values": [
{
"id": 3,
"value": 300
},
{
"id": 4,
"value": 200
}
]
},
{
"id": 3,
"values": [
{
"id": 5,
"value": 300
}
]
}
]
}
// data3.json ~ data7.json も同じフォーマットのデータが続く
ファイルの内容を簡単に説明すると、オブジェクトの第1階層のtypeはデータの種類を表していてファイル毎に違っています。ファイルは1から7まであるので、7種類のデータが存在するという事になります。次に、オブジェクトの第1階層のusersですが、これはユーザごとの値を配列形式で持っています。
今回はこのような形式のjsonから、特定の条件のデータのみ抽出して、内容の確認を行うという事をしました。
結論
結論を先に書くと、次のコマンドを実行して、ユーザID:2のデータを抽出しました。
複雑になるので、解説時はdata1とdata2のみを対象として書かせていただきます。
$ cat data1.json data2.json | jq -s '.[0].users + .[1].users|.[]|select(.id==2)' | jq -s
[
{
"id": 2,
"values": [
{
"id": 2,
"value": 200
}
]
},
{
"id": 2,
"values": [
{
"id": 3,
"value": 300
},
{
"id": 4,
"value": 200
}
]
}
]
解説
cat data1.json data2.json | jq -s '.[0].users + .[1].users|.[]|select(.id==2)' | jq -s
このコマンドをいくつかに分解して解説します。
cat data1.json data2.json | jq -s
まず、jqの基本的な使い方ですが、jqは標準入力から受け取ったJSONを加工して標準出力に出力するコマンドです。
複数のファイルからデータを取得したいので、catコマンドでファイルを結合してjqに渡しています。
また、-s
オプションをつける事で、複数のファイルを結合した際に、それらを配列にしてくれます。
ここまでの部分を実行すると、次のような結果が得られます。
$ cat data1.json data2.json | jq -s
[
{
"type": "タイプ1",
"users": [
{
"id": 1,
"values": [
{
"id": 1,
"value": 100
}
]
},
{
"id": 2,
"values": [
{
"id": 2,
"value": 200
}
]
}
]
},
{
"type": "タイプ2",
"users": [
{
"id": 2,
"values": [
{
"id": 3,
"value": 300
},
{
"id": 4,
"value": 200
}
]
},
{
"id": 3,
"values": [
{
"id": 5,
"value": 300
}
]
}
]
}
]
.[0].users + .[1].users
次に、jqで配列を扱う方法ですが、.[index]
という形式で配列の要素にアクセスできます。なので、.[0].users
は1つ目のファイルのusersを、.[1].users
は2つ目のファイルのusersを取り出しています。
また、配列の結合は +
で行えます。なので、.[0].users + .[1].users
は1つ目のファイルと2つ目のファイルのusers配列を結合しているという事になります。
ここまでの部分を実行すると、次のような結果が得られます。
$ cat data1.json data2.json | jq -s '.[0].users + .[1].users'
[
{
"id": 1,
"values": [
{
"id": 1,
"value": 100
}
]
},
{
"id": 2,
"values": [
{
"id": 2,
"value": 200
}
]
},
{
"id": 2,
"values": [
{
"id": 3,
"value": 300
},
{
"id": 4,
"value": 200
}
]
},
{
"id": 3,
"values": [
{
"id": 5,
"value": 300
}
]
}
]
|.[]|select(.id==2)
次に、users配列から特定のユーザIDのデータを抽出します。jqでは |(パイプ)を使うことで、それまでの結果に対して処理をおこなう事ができます。selectを行う際に配列のままだと、配列の要素がすべて抽出されてしまうので、配列の要素を展開するために、|.[]
を挟んでいます。取り出したオブジェクトに対して、selectを行う事で、条件に合致するオブジェクトのみを抽出しています。
ここまでの実行結果は以下のようになります。
ユーザIDが2のデータのみに絞り込みをすることができました。
$ cat data1.json data2.json | jq -s '.[0].users + .[1].users|.[]|select(.id==2)'
{
"id": 2,
"values": [
{
"id": 2,
"value": 200
}
]
}
{
"id": 2,
"values": [
{
"id": 3,
"value": 300
},
{
"id": 4,
"value": 200
}
]
}
jq -s
ここまでの結果でもやりたい事は達成できていますが、json形式から逸脱してしまっているので、最後にもう一度jq -s
を実行して、オブジェクトを配列に詰め直しています。
まとめ
今回はjqを使って、複数のjsonファイルから特定のデータを抽出する方法を紹介しました。
jqはある程度ファイルサイズが大きくなっても使うことができ、インストールも手軽に行える点が良いと思いました。
参考
スペースを簡単に貸し借りできるサービス「スペースマーケット」のエンジニアによる公式ブログです。 弊社採用技術スタックはこちら -> whatweuse.dev/company/spacemarket
Discussion