これらの jq フィルターは、選択、マップ、リデュース、並べ替え、デフォルト、および書式設定など、毎日行うジョブを処理します。これらの重要な機能の使用方法を説明と例で確認します。
一般的なデータベースのような操作であるこのパターンは、jq が SQL のエミュレーションにどれだけ近づくことができるかを示しています。オブジェクトのセットをフィルタリングし、プロパティ値に基づいて一部を取得する必要がある場合は、select 関数を使用します。
map(select(.property == "value"))
このフィルターは、オブジェクトが配列内にあり、その配列内にオブジェクトを保持したいことを前提としています。たとえば、次の入力があったとします。
( "fruits": map(.fruit) , "fruits": map(.fruit) )
このフィルターを使用して項目を選択できます。
map(select(.age == 10))
jq は、文字列の書式設定やエスケープに使用できる、@ で始まる一連のフィルターをサポートしています。これらを使用して、CSV、HTML、base64、さらには URI 互換エンコーディングでファイルを生成できます。
@uri
このフィルターは、予約された各 URI 文字を %XX シーケンスにマッピングすることにより、パーセント エンコーディングを適用します。一般的な予約文字には、:、@、? が含まれます。
フィルターを使用するには、次のように文字列を渡すだけです。
jq '@uri' <<< '"Ask yourself: what can I do for my country?"'
結果の文字列には、元の予約文字ごとに %XX エンコーディングが含まれます。
多くの jq タスクは、オブジェクトの変換 (データをある構造から別の構造に変換する) の範疇にあります。
マップ関数は、配列内の各値、またはオブジェクトの各プロパティに別の関数を適用します。これは、データをある形式から別の形式に変換するための完璧な汎用方法です。
この単純なデータを例として取り上げます。
(
add ,
add ,
{ "fruit": "apple", "price": 1 }
)
ここで、次の概要データを生成するとします。
{
"fruits": ("apple", "banana"),
"total": 4
}
まず、必要な出力を表す構造体に入力をマッピングします。
jq '{ "fruits": (), "total": 0 }' fruits.json
次に、元のデータからフェッチする必要がある各データに対してマップを使用します。
jq '{ "fruits": map(.fruit) | unique, "total": map(.price) | add }' fruits.json
Reduce は、プログラミング、特にデータベース操作やビッグ データ処理において非常に一般的な関数です。 jq では、reduce 構文を使用してセットを処理し、そこから単一の値を導出できます。一般的な構文は次のとおりです。
reduce expression as $var (init; update)
init 式は結果の初期値を定義しますが、update は $var を参照して結果を変更する式である必要があります。したがって、数値リストの合計を計算するには、次のようにします。
jq 'reduce .() as $item (0; . + $item)' <<< '(1,2,3)'
同様に、文字列のセットを 1 つの文字列に結合できます。
jq 'reduce .() as $item (""; . + $item + " ")' <<< '("hello","world")'
場合によっては、期待するほどきれいではないデータを操作する必要があることがあります。たとえば、数値が文字列に埋め込まれている場合、それを抽出してさらに処理することができます。
の match 関数は正規表現検索を実行し、一致するそれぞれの値を出力します。文字列に対して実行すると、位置 (オフセット) や一致した文字列など、一致に関する情報を含むオブジェクトが返されます。
したがって、これを使用して数値を抽出するには、次のようにアクセスできます。 string 結果からのプロパティ:
jq '. | match("\d+") | .string' <<< '"1600 Pennsylvania Avenue NW"'
jq は、一般的なデータ型に便利な関数を多数提供しています。そのような型の 1 つは date であり、ほとんどすべての日付書式設定ライブラリは、C 標準ライブラリの strftime 関数に依存しています。 jq には strftime 用の独自のインターフェイス ラッパーがあり、Unix エポック以降の現在時刻を取得する now のような関数もあります。
jq -n now
strftime 関数は、この関数の OS のバージョンがサポートするあらゆる形式を受け入れます。変換文字の例には、完全な年を表す %Y、エポックからの秒数を表す %s、曜日の完全名を表す %A などがあります。 %+ は便利な完全な日付と時刻の形式です。
jq -n 'now | strftime("%+")'
データからオブジェクトを作成している場合、値が使用できない場合にデフォルトを指定すると便利です。このデータを例として取り上げます。
({
"name": "pigeon",
"type": "omnivore"
},{
"name": "penguin",
"type": "carnivore"
},{
"name": "woodpecker"
})
デフォルト値を指定する標準的な方法では、if-then-else ブロックを使用してプロパティをチェックします。まだ存在しない場合、フィルターは固定のデフォルト値を使用して追加する必要があります。
jq < birds.json '.() | if (.type) then . else . + {"type": "omnivore"} end'
ここで、条件は type プロパティの存在をチェックします。存在する場合、ID フィルター (.) は単にオブジェクトをコピーします。ただし、そうでない場合は、+ 演算子を使用して、そのオブジェクトと、type プロパティのみを含むオブジェクトと、デフォルト値が結合されます。これにより、デフォルト値が適用された元のデータが得られます。
前の例では、+ 演算子を使用して 2 つのオブジェクトを結合しました。基本的なケースではこれで問題ありません。
jq -n '{ "foo": 1 } + { "bar": 42 }'
-n オプションは、入力の提供を要求するのではなく、null 入力を使用するように jq に指示するため、この種の演算子のテストに最適です。
ただし、+ 演算子は浅いマージのみを実行するため、より複雑なオブジェクトはこのアプローチでは失敗します。たとえば、次のフィルタでは完全なマージは生成されません。
{ "name": { "first": "John", "last": "Doe" } }
+
{ "name": { "first": "Jane" } }
代わりに、次のオブジェクトが返されます。
{
"name": {
"first": "Jane",
}
}
それが理にかなっている場合もありますが、深いマージが必要な場合は、代わりに * 演算子を使用する必要があります。