トラック
/
jq
jq
/
シラバス
/
オブジェクト
オブ

オブジェクト の jq

4個の演習

オブジェクトについて

JSONのオブジェクトは、他の言語の用語で呼ぶなら「ハッシュ」「マップ」「辞書」にあたります。

JSONでは、_オブジェクト_を次のように定義しています。

オブジェクトとは、名前と値のペアの、順序を持たない集合です。 オブジェクトは{左波括弧で始まり、}右波括弧で終わります。 各_名前_の後ろには:コロンが続き、_名前と値のペア_は,カンマで区切られます。

_名前_は文字列でなければなりません。 _名前_は_キー_とも呼ばれます。

_値_はどのJSON型でもかまいません。 同じオブジェクトの中でも、次の例のように_値_ごとに違う型を持てます。

{
  "name": "Jane",
  "age": 42,
  "pets": ["cat", "fish"],
  "address": {"street": "123 Main St", "city": "Springfield"}
}

_最後_のキーと値のペアの後ろには、カンマを付けません。

オブジェクトの作成

名前と値のペアは波括弧でまとめます。 名前は文字列でなければなりませんが、名前が識別子に似た形(英数字とアンダースコアで構成され、数字で始まらないもの)であれば、引用符でくくる必要はありません。

{name: "Jane", age: 42}

_識別子に似た形_でないキーを使うこともできます。 その場合は引用符でくくるだけです。

{"first name": "Jane", "last name": "Lopez", age: 42}

名前が式の結果である場合、その式は括弧でくくる必要があります。

$ echo "Jane" | jq -Rc '{.: 42}'
jq: error: syntax error, unexpected '.' (Unix shell quoting issues?) at <top-level>, line 1:
{.: 42}
jq: error: May need parentheses around object key expression at <top-level>, line 1:
{.: 42}
jq: 2 compile errors

$ echo "Jane" | jq -Rc '{(.): 42}'
{"Jane":42}

省略記法

オブジェクトの作成でよくあるケースには、省略記法が用意されています。

  1. 入力オブジェクトのキーと値のペアを再利用する場合。

    $ jq -n '$ENV | {USER: .USER, EDITOR: .EDITOR}'
    {
      "USER": "glennj",
      "EDITOR": "vim"
    }
    

    $ENVは、環境の名前と値のペアを保持するオブジェクトです。

    繰り返しになるkey: .keyのペアは、keyだけでも書けます。

    $ jq -n '$ENV | {USER, EDITOR}'
    {
      "USER": "glennj",
      "EDITOR": "vim"
    }
    
  2. 同様に、変数を使う場合にも省略記法があります。

    $ jq -cn '"foo" as $a | "bar" as $b | {a: $a, b: $b}'
    {"a":"foo","b":"bar"}
    
    $ jq -cn '"foo" as $a | "bar" as $b | {$a, $b}'
    {"a":"foo","b":"bar"}
    

インデックス

値はドット記法でオブジェクトから取り出します。

{name: "Jane", age: 42} | .age    # => 42

キーを識別子として参照できない場合は、角括弧記法を使います。

"name" as $key | {name: "Jane", age: 42} | .$key    # => error
"name" as $key | {name: "Jane", age: 42} | .[$key]  # => "Jane"

キーがオブジェクトにない場合、結果はnullです。

{name: "Jane", age: 42} | .sport  # => null

入れ子の値のインデックス

APIのクエリ結果を解析するとき、この操作を何度も何度も行うことになるでしょう。

配列やオブジェクトを値として持つオブジェクトが与えられたとき、インデックス式を「つなげて」書くことができます。

{
  "name": "Jane",
  "age": 42,
  "pets": ["cat", "fish"],
  "address": {"street": "123 Main St", "city": "Springfield"}
}
| (
  .pets[1],       # => "fish"
  .address.city   # => "Springfield"
)

キーと値のペアの追加と変更

配列に新しいキーと値のペアを追加したり、既存のキーの値を更新したりするには、左辺にインデックス式を置いて=代入演算子を使います。

{name: "Jane", age: 42} | .sport = "tennis" | .age = 21
# => {
#      "name": "Jane",
#      "age": 21,
#      "sport": "tennis"
#    }

+演算子はオブジェクトを_マージ_します。

{Richard: 54} + {Jane: 42}
# => {
#      "Richard": 54,
#      "Jane": 42
#    }

キーの削除

キーを削除するにはdel関数を使います。 更新後のオブジェクトが返ります。

{name: "Jane", age: 42} | del(.age)   # => {"name": "Jane"}

delへの入力は、オブジェクト内のキーを指すインデックス式(ドット記法または角括弧記法)です。 jqではこれをパス式と呼びます。 ただ文字列を渡すだけでは不十分です。

{name: "Jane", age: 42} | del(name)        # error: name/0 is not defined
{name: "Jane", age: 42} | del("name")      # error: Invalid path expression with result "name"
{name: "Jane", age: 42} | del(.name)       # OK
{name: "Jane", age: 42} | del(.["name"])   # OK

キーの有無の確認

  • オブジェクトがキーを持っているか調べるには、has関数を使います。

    {name: "Jane", age: 42} as $example
    |
      ($example | has("name")),    # => true
      ($example | has("sport"))    # => false
    
  • キーがオブジェクトの中にあるかどうかはinで調べます。

    {name: "Jane", age: 42} as $example
    |
      ("name"  | in($example)),    # => true
      ("sport" | in($example))     # => false
    

キーや値の一覧

すべてのキーの一覧を出力するには、keys関数を使います。

{name: "Jane", age: 42} | keys   # => ["age", "name"]

keysはキーを_ソート_することに注意してください。 元の順序でキーを取り出すには、keys_unsortedを使います。

すべての_値_を一覧にする同等の関数はありません。 ただし、.[]フィルターはオブジェクトの値を_ストリーム_として出力し、そのストリームは[...]配列コンストラクターで取り込むことができます。

[{first: "Jane", last: "Lopez", status: "awesome!"} | .[]]
# => ["Jane", "Lopez", "awesome!"]

繰り返し

  • map_values(filter)関数は、フィルターをオブジェクト内の各_値_に適用します。

    {first: "Jane", last: "Lopez", status: "awesome!"}
    | map_values(ascii_upcase)
    # => {"first": "JANE", "last": "LOPEZ", "status": "AWESOME!"}
    
  • オブジェクトを繰り返し処理するには、まずそれをキーと値のオブジェクトの配列に変換する必要があります。 to_entries関数がそれを行います。

    {name: "Jane", age: 42} | to_entries
    # => [
    #      {
    #        "key": "name",
    #        "value": "Jane"
    #      },
    #      {
    #        "key": "age",
    #        "value": 42
    #      }
    #    ]
    

    ここまでくれば、mapのような配列の繰り返し関数を使えます。

  • from_entries関数はその逆で、キーと値のオブジェクトの配列をオブジェクトに変換します。

    [
      {"key":"name", "value":"Jane"},
      {"key":"age", "value":42}
    ] | from_entries                  # => {"name": "Jane", "age": 42}
    
  • オブジェクト内の_各_キーと値のペアにフィルターを適用するには、with_entries(filter)関数を使います。

    たとえば、名前を年齢に対応させたオブジェクトが与えられたとき、キーと値を次のように入れ替えられます。

    {"Jane": 42, "Richard": 54}
    | with_entries({key: (.value | tostring), value: .key})
    

    は次を出力します。

    {
      "42": "Jane",
      "54": "Richard"
    }
    

    with_entries(filter)は次と同じです。

    to_entries | map(filter) | from_entries
    
GitHubで編集 リンクは新しいウィンドウまたはタブで開きます

オブジェクトを学習する

練習はロックされています

オブジェクトを練習するには、あと4個の演習のロックを解除してください