web-dev-qa-db-ja.com

jq:オブジェクトからキーのサブセットを選択する

配列からのキーの入力json文字列を指定すると、元のオブジェクトと入力配列にキーが含まれるエントリのみを含むオブジェクトを返します。

私には解決策がありますが、それはエレガントではなく({($k):$input[$k]}は特に不格好に感じます...)、これは私が学ぶチャンスだと思います。

jq -n '{"1":"a","2":"b","3":"c"}'   \
    | jq --arg keys '["1","3","4"]' \
    '. as $input 
     | ( $keys | fromjson )
     | map( . as $k
          | $input
          | select(has($k))
          | {($k):$input[$k]}
          )
     | add'

これをクリーンアップする方法はありますか?

jqを使用してネストされたJSONオブジェクトから選択したプロパティを抽出する は良い出発点であるように感じますが、それを機能させることはできません。

9
Jon

内部チェックによる解決策:

jq 'with_entries(select([.key] | inside(["key1", "key2"])))'
8
user5672998

このフィルターを使用できます:

with_entries(
    select(
        .key as $k | any($keys | fromjson[]; . == $k)
    )
)
8
Jeff Mercado

内部演算子はほとんどの時間機能します。ただし、内部演算子に副作用があることがわかりました。入力が{ "key1": val1, "key2": val2, "key12": val12 }であり、inside(["key12"])で選択すると、"key1""key12"の両方が選択される場合があります。

完全一致が必要な場合は、in演算子を使用します。このようにすると、.key2.key12のみが選択されます

jq 'with_entries(select(.key | in({"key2":1, "key12":1})))'

in演算子はオブジェクトからのキーのみ(または配列からのインデックスexists?)をチェックするため、ここでは目的のキーをキーとしてオブジェクト構文で記述する必要がありますが、値は重要ではありません。 in演算子の使用は、この目的には完全ではありません。JavascriptES6に、jqビルトインとして実装されるAPIの逆バージョンが含まれていることを確認したいと思います

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/includes

jq 'with_entries(select(.key | included(["key2", "key12"])))'

アイテムをチェックするには.keyは配列からincluded?です

1
user5672998

ジェフの答えには、いくつかの不必要な非効率性があります。どちらも、--argjson keysの代わりに--arg keysが使用されていると仮定して、次のように対処します。

with_entries( select( .key as $k | $keys | index($k) ) )
1
peak

ここにいくつかの追加の説明があります

入力オブジェクトの場合{"key1":1, "key2":2, "key3":3}目的のキーのセットに含まれていないすべてのキーを削除したい["key1","key3","key4"]

 jq -n --argjson desired_keys '["key1","key3","key4"]'  \
       --argjson input '{"key1":1, "key2":2, "key3":3}' \
    ' $input
    | with_entries(
          select(
              .key == ($desired_keys[])
          )
       )'

with_entriesは、{"key1":1, "key2":2, "key3":3}を次のキーと値のペアの配列に変換し、selectステートメントを配列にマップしてから、結果の配列をオブジェクトに戻します。

これがwith_entriesステートメントの内部オブジェクトです。

[
  {
    "key": "key1",
    "value": 1
  },
  {
    "key": "key2",
    "value": 2
  },
  {
    "key": "key3",
    "value": 3
  }
]

次に、この配列から基準を満たすキーを選択できます。

ここで魔法が起こります...このコマンドの途中で何が起こっているかを見てみましょう。次のコマンドは、展開された値の配列を取得し、それらを選択可能なオブジェクトのリストに変換します。

jq -cn '{"key":"key1","value":1}, {"key":"key2","value":2}, {"key":"key3","value":3}
      | select(.key == ("key1", "key3", "key4"))'

これにより、次の結果が得られます

{"key":"key1","value":1}
{"key":"key3","value":3}

With entryコマンドは少し注意が必要ですが、フィルターを使用し、次のように定義されていることを覚えておくのは簡単です。

def with_entries(f): to_entries|map(f)|from_entries;

これはと同じです

def with_entries(f): [to_entries[] | f] | from_entries;

人々を混乱させる質問の他の部分は、==の右側にある複数の一致です。

次のコマンドについて考えてみます。出力は、すべての左側のリストと右側のリストの外部生成であることがわかります。

jq -cn '1,2,3| . == (1,1,3)'
true
true
false
false
false
false
false
false
true

その述語がselectステートメントにある場合、述語がtrueのときに入力を保持します。ここでも入力を複製できることに注意してください。

jq -cn '1,2,3| select(. == (1,1,3))'
1
1
3
0
Jon