次のような行を含むファイルがあります。
{"items":["blue","green"]}
{"items":["yellow","green"]}
{"items":["blue","pink"]}
jq を使用して、「items」配列に「blue」が含まれるJSON値のみを選択して表示するにはどうすればよいですか?
したがって、出力は次のようになります。
{"items":["blue","green"]}
{"items":["blue","pink"]}
答えを見つけた
jq 'select(.items | index("blue"))'
2017年1月30日に、JSONエンティティがストリームに含まれているかどうかを効率的にテストするために、IN
という名前の組み込みが追加されました。また、アレイのメンバーシップを効率的にテストするためにも使用できます。この場合、関連する使用法は次のようになります。
select( .items as $items | "blue" | IN($items[]) )
JqにIN/1
がない場合、jqにfirst/1
がある限り、次の同等の定義を使用できます。
def IN(s): . as $in | first(if (s == $in) then true else empty end) // false;
ここでのany/0
の使用は比較的非効率的です。 any/1
の使用と比較して:
select( any( .items[]; . == "blue" ))
(実際には、index/1
は通常十分に高速ですが、現在の実装(jq 1.5および少なくとも2017年7月までのバージョン)は最適ではありません。)
確かに機能しますが、contains
を使用する方が正しいでしょう。混乱を招く可能性があるので、その使用は避けます。 index("blue")
は0
そして真実の値であるとは考えず、結果から除外されることを期待するかもしれません。
代わりにこのフィルターの使用を検討してください:
select(.items | contains(["blue"]))
これには、単に配列にさらに追加することで、複数の一致を持つ項目が必要な場合に機能するという追加の利点があります。
ウィルがコメントで指摘したように、これは正確ではありません。文字列は、ここで部分文字列マッチング(contains
が再帰的に使用されます)を使用して比較されます。
振り返ってみると、contains
は思ったように機能しませんでした。 index
を使用しても機能しますが、個人的には使用しません。アイテムがコレクションに含まれているかどうかを、自分にとって間違っていると思われるインデックスを探すことで判断することについて何かがあります。 contains
を使用する方が理にかなっていますが、この情報を考慮すると、この場合は理想的ではありません。
正しく動作するはずの代替方法を次に示します。
select([.items[] == "blue"] | any)
または、より多くの値を照合できるようにする場合は、よりスケーラブルな方法を使用します。
select(.items as $values | ["blue", "yellow"] | map([$values[] == .] | any) | all)
オブジェクトの同じ状況で「正規表現」を使用する必要がありました。 (もちろん、別のコンテキストでは)。これらのページで必要な解決策が見つからなかったため、コードを記述しました。これは、誰かに役立つ場合があります。
たとえば、正規表現を使用して青色を一致させるには:
jq 'select(.items[]|test("bl.*"))' yourfile.json