jqでJSONをunnestする

こんな感じのJSONを、

[
  {"name": "a", "value": [1, 2]},
  {"name": "b", "value": [3, 5]}
]

こうしたい。

[
  {"name": "a", "value": 1},
  {"name": "a", "value": 2},
  {"name": "b", "value": 3},
  {"name": "b", "value": 5}
]

基本的にこういう操作はMillerでできるといいと思うんですが、今のところMillerは配列を含むJSONを扱えません。(--json-skip-arrays-on-inputをつければスキップは可能)

仕方ないのでjqでやる方法を調べたのでメモ。こうです。

$ echo '[{"name": "a", "value": [1, 2]}, {"name": "b", "value": [3, 5]}]' | jq '
> .[]
> | .value as $v
> | del(.value)
> | (. + {"value": $v[]})
> '

asは、ある値を変数($+変数名)に格納します。 del()は、指定したフィールドを消します。ここでは、ネストしているvalueを消していますが、そのあとで使いたいのでdel()する前にasで値を別場所に取っておきます。 で、一番最後ですが、jqは+JSONを結合することができます。.(すべてのフィールド)と{"value": $v[]}を結合します。ちなみに後者ですが、$vだと[1, 2]のように元の配列ですが$v[]とすることで12のような要素に展開できます。

ということで、できるっちゃできるわけですが、めんどくさいのでMiller対応してくれー…。Issueは立ててみましたがちょっと先になりそうです。

github.com

まあ、上のIssueに書いているように、Rでいいじゃんという話ではあります。

json_obj <- jsonlite::fromJSON('[{"name": "a", "values": [1, 2]}, {"name": "b", "values": [3, 5]}]', flatten = TRUE)
tidyr::unnest(json_obj, values)
#>   name values
#> 1    a      1
#> 2    a      2
#> 3    b      3
#> 4    b      5