小技

日々の仕事の中で調べたり発見したりしたことを書き留めていくブログ

jq で オブジェクトのキーまたは値を取得する

前回の記事 の中で、オブジェクトの全てのキーや値を取得する方法に触れました。 やり方がいくつかありそうだったので、まとめてみました。

オブジェクトの全てのキーの取得

下記のような JSON に対して、keys 関数を用いることで、キーの一覧を取得できます。

$ cat sample.jsson
{
    "key0": "value0",
    "key2": "value2",
    "key1": "value1"
}
$ jq keys sample.json
[
  "key0",
  "key1",
  "key2"
]

しかしこれは、よく見るとソートされて順番が変わっています。 keys に対して keys_unsorted という関数もあり、これを用いることで、元の順序通りにキーの一覧を得ることができます。

(jq のマニュアルより)

keys, keys_unsorted
The builtin function keys, when given an object, returns its keys in an array.

The keys are sorted "alphabetically", by unicode codepoint order. This is not an order that makes particular sense in any particular language, but you can count on it being the same for any two objects with the same set of keys, regardless of locale settings.

When keys is given an array, it returns the valid indices for that array: the integers from 0 to length-1.

The keys_unsorted function is just like keys, but if the input is an object then the keys will not be sorted, instead the keys will roughly be in insertion order.

$ jq keys_unsorted sample.json
[
  "key0",
  "key2",
  "key1"
]

オブジェクトの全ての値の取得

前回の記事 でも触れたように、.[] をオブジェクトに対して使うことで、全ての値を得ることができます。 この場合は結果が配列とはならないので、keyskeys_unsorted のように配列としたい場合は [] で囲んでやる必要があります。

$ jq .[] sample.json
"value0"
"value2"
"value1"
$ jq [.[]] sample.json
[
  "value0",
  "value2",
  "value1"
]

また、こちらは値の順番がそのままで出力されます。 ソートした結果が欲しい場合は、当然ですが | sort を追加する必要があります。

全てのキーと値の組み合わせを配列として取得

キーと値で取得の仕方があまりにも違うので、両方に対応できる汎用的な方法がないか調べたところ、to_entries という関数があります。

These functions convert between an object and an array of key-value pairs. If to_entries is passed an object, then for each k: v entry in the input, the output array includes {"key": k, "value": v}.

$ jq to_entries sample.json
[
  {
    "key": "key0",
    "value": "value0"
  },
  {
    "key": "key2",
    "value": "value2"
  },
  {
    "key": "key1",
    "value": "value1"
  }
]

これだと、キーと値どちらにも対応できそうです。 対応するキーと値の組み合わせとして出力されるので、片方だけソートされているということもありません。

$ jq 'to_entries[].key'  sample.json
"key0"
"key2"
"key1"
$ jq 'to_entries[].value'  sample.json
"value0"
"value2"
"value1"

大量のデータを処理する場合の効率という点ではわかりませんが、覚えやすさとしてはこのやり方だけ覚えておいてもいいかもしれません。

参考