LoginSignup
14
13

More than 5 years have passed since last update.

jqを使ってJsonの深いネストにあるキーの値を抽出する方法(上の階層のキーがわからない時)

Last updated at Posted at 2016-06-03

jqでJSONを整形してる時に、深いネストのキーを検索する方法のメモ
ただ、この記事はjq歴3時間のド素人書いたやつなので、もっといい方法が絶対あるはず(と言うか誰かおしえてください)

キー名でのフィルターのかけ方

例えば以下のJsonファイルで「key1」というキーを持つ文字列だけを取り出したい場合は以下のように書く。

test.json
{
    "key1":{
        "key2":"value1",
        "key3":"value2"
    },
    "foo":"bar"
}
Terminal
$ jq '.key1' test.json
{
  "key2": "value1",
  "key3": "value2"
}

要するに.hogeって書けば、ドットの後に続けた文字列のキーに該当する値を返してくれる。これは連続で書くこともできて、例えば以下のように書くと、ネストを掘りながらフィルターを掛けることができる。

Terminal
$ jq '.key1.key2' test.json
"value1"

ただしこのフィルターは1階層目のキーしか見てくれないので、例えば以下のように書いてしまうとnullが帰ってきてしまう。

Terminal
$ jq '.key2' test.json
null

つまりこのフィルターで値をとってきたい場合、「抽出したいキーの名前はわかってるんだけど、その上の階層でどんなキーが指定されてるのかわからなくて、そもそも何階層目にあるかわからない」って時には上手く動かない。

要するにどんな階層にいても目的のキーを抽出してくれるgrep的な何かがほしいわけです。(まあそれこそgrep使えばいいのかもしれないけど)。

recurseを使う

resurseってのはJsonのオブジェクトの中身を再帰的に展開してくれるフィルター。たぶん見てみるのが一番早いと思う。

test.json
{
    "key1":{
        "key2":"value1",
        "key3":"value2"
    },
    "foo":"bar"
}
Terminal
$ jq 'recurse' test.json
{
  "key1": {
    "key2": "value1",
    "key3": "value2"
  },
  "foo": "bar"
}
{
  "key2": "value1",
  "key3": "value2"
}
"value1"
"value2"
"bar"

とまあこんな感じでオブジェクトの中身を展開してくれる。こいつを使うと、どんなに深いネストの中にあるキーで強制的に1階層目に持ってこれるわけです。代わりに余計なものがいっぱいくっついてくるけど。

なので、select関数を使って、「key2」を一階層目のキーに持たないオブジェクトを削除する。

test.json
{
    "key1":{
        "key2":"value1",
        "key3":"value2"
    },
    "foo":"bar"
}
Terminal
$ jq 'recurse | select(.key2)' test.json
{
  "key2": "value1",
  "key3": "value2"
}

ここでの「|」は、シェルの「|」とほぼ同じ意味で、左の出力結果をそのまま右のフィルターの入力パラメータに利用する事ができる。

ここまでくればあとはフィルターをかけるだけ

Terminal
$ jq 'recurse | select(.key2) | .key2' test.json
"value1"

略式でこう書くこともできる。

Terminal
$ jq 'recurse | select(.key2).key2' test.json
"value1"

こんな感じで無事「key2」の値を取ってくることができた。

ちなみにselect関数を使わないと、以下の様な感じで「key2」を持たないオブジェクトに対するフィルター結果であるnullが残ってしまう。

test.json
{
    "key1":{
        "key2":"value1",
        "key3":"value2"
    },
    "foo":"bar"
}
Terminal
$ jq 'recurse | .key2' test.json
null
"value1"

recurse応用

recurse関数は以下のように再帰的にフィルターをかけながら展開することもできる(と言うかこっちが本来の使い方?)

test.json
{
    "key1":{
        "key2":"value1",
        "key3":"value2"
    },
    "foo":"bar"
}
Terminal
$ jq 'recurse(.key1)' test.json
{
  "key1": {
    "key2": "value1",
    "key3": "value2"
  },
  "foo": "bar"
}
{
  "key2": "value1",
  "key3": "value2"
}

おんなじキー名が連続してネストされているような場合に使うらしい。そんな時あるのかな・・・

より詳しい使い方は公式サイトのマニュアル見てください。
日本語訳してくれているページも参考になりました。感謝
ブラウザでjqを試し打ちできるページもあるので、いろいろ遊ぶと楽しいです。

14
13
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
14
13