JQ

2017-08-18 7 views
0

でネストされた配列の値からのみ所望の特性を取得する構造は次のようになります。JQ

{ 
    "catalog": [ 
    { 
     "name": "X", 
     "catalog": [ 
     { "name": "Y", "uniqueId": "Z" }, 
     { "name": "Q", "uniqueId": "B" } 
     ] 
    } 
    ] 
} 

これは、既存の構造が多く他のプロパティは、各レベル(https://gist.github.com/ajcrites/e0e0ca4ca3a08ff2dc401ec872e6094c)である除いて次のようになります。私はそれらをフィルタリングして、このように特に見えるJSON形式を取得したいだけです。

私は:jq '.catalog'で始まりましたが、これは配列だけを返します。私はまだcatalogプロパティ名が欲しいです。私はjq '{catalog: .catalog[]}でこれを行うことができますが、これは各カタログオブジェクトを個別に出力するので、出力全体が無効になります。私はまだプロパティが配列内にあることを望んでいます。 jqを使用して配列内の特定のプロパティキー値をフィルタリングする方法はありますか?

+0

現在の入力に望ましい出力を表示します。また、入力は有効ではありません。json:配列内に '' name ":" Y "'という表記を使用することはできません。 – RomanPerekhrest

+0

@RomanPerekhrestは望ましい出力です。入力は同じで、より多くのプロパティを持っています。私は質問にサンプルを含めました –

+0

私は期待される出力を与える解決策を持っています。しかし私は普遍的なアプローチではなく、「ハック」と呼ぶことができます。だから私はそれを投稿しなかったのです – RomanPerekhrest

答えて

2

以下は、所望の出力に与えられた入力を変換してもあなたが望むことがあります

{catalog} 
| .catalog |= map({name, catalog}) 
| .catalog[].catalog |= map({name, uniqueId}) 
| .catalog |= .[0:1] 

しかし、それはあなたが議論していないとして、これは、あなたが望むもの、本当にあると私にははっきりしていません指定されたJSON入力の複製。だから、あなたは本当に上記の最後の行を望んでいないかもしれません、または別の方法で重複を扱うことを望むかもしれません、または...

とにかく、ここで物事を単純にすることの秘訣は|=です。

delを使用して不要なプロパティを削除することもできます(ただし、必要なものを選択するのではなく)。

+0

'| ='が何をするのか少し説明できますか? –

+0

.a | = Xは、次のような割り当てです。.a =(.a | X)。詳細は、マニュアルを参照してください。また、https://jqplay.org/ – peak

+0

を使用することもできます。これは私に必要なものを与えました。ごめん、少し不明です。実際に '| = map()'は私が必要としていたもののほとんどであり、あなたの説明にも意味があります。 –

0

あなたはこれが生成されますあなたのあなたが見ることができるように、[パス、値]列のストリームにsample.json

jq -c tostream sample.json 

を実行することにより、変換することtostreamを使用して開始することができ

[["catalog",0,"catalog",0,"name"],"Y"] 
[["catalog",0,"catalog",0,"prop11"],""] 
[["catalog",0,"catalog",0,"uniqueId"],"Z"] 
[["catalog",0,"catalog",0,"uniqueId"]] 
[["catalog",0,"catalog",1,"name"],"Y"] 
[["catalog",0,"catalog",1,"prop11"],""] 
... 

還元およびセットパスは、に変換するために使用できます任意のレベルでプロパティを省略することが容易になります。 は、例えば、以下は「小道具」で始まるの葉の属性が削除されます:あなたのsample.json

reduce (tostream|select(length==2)) as [$p,$v] (
    {}; 
    if $p[-1]|startswith("prop") 
    then . 
    else setpath($p;$v) 
    end 
) 

目標は、特定のプロパティを削除する場合、これは

{ 
    "catalog": [ 
    { 
     "catalog": [ 
     { 
      "name": "Y", 
      "uniqueId": "Z" 
     }, 
     { 
      "name": "Y", 
      "uniqueId": "Z" 
     } 
     ], 
     "name": "X" 
    }, 
    { 
     "catalog": [ 
     { 
      "name": "Y", 
      "uniqueId": "Z" 
     }, 
     { 
      "name": "Y", 
      "uniqueId": "Z" 
     } 
     ], 
     "name": "X" 
    } 
    ] 
} 
0

を生成し、その後、1はwalk/1を使用して、そうでした。フォーカスが特定の特性を保持上にある場合、同じアプローチはまた、例えば、適用可能であろう

walk(if type == "object" 
     then with_entries(select(.key|startswith("prop") | not)) 
     else . end) 

たとえば、名前が「プロップ」で始まるプロパティを削除します:

walk(if type == "object" 
    then with_entries(select(.key == "name" or .key == "uniqueId" or .key == "catalog")) 
    else . end) 
0

保存したいjsonへのパスを含むファイルを構築することができます(配列として表現します)。次に、それらのパスに収まらない値を除外します。

paths.json:そのパスに基づいて、フィルタ値その後

["catalog","name"] 
["catalog","catalog","name"] 
["catalog","catalog","uniqueId"] 

。ストリームを使用すると、これらのパスに直接アクセスできるので、これを行うには最適な方法です:

+0

私の解決方法で 'fromstream'を使ってみましたが、何も返さなかった(' fromstream'過去に私が 'truncate_stream'と一緒に使っていたときに働いていました)が、私のreduce select(length == 2)が破棄する' length == 1'パスを慎重に入れていることがわかります。私はなぜ 'tostream'が' length == 1'のパスを生成したのか理解できませんでしたが、私は今知っていると思います。 – jq170727

+1

長さ1のエントリは、対応するオブジェクトまたは配列の定義の終わりを示します。これらのエントリがなければ、fromstreamは対応する値をいつ閉じるかを知りません。開いたまま残ったものはすべて結果から除外されます。少なくとも、それは私がそれを理解する方法です。 jqのストリームは常に私にとって大きな疑問符でしたが、それを効果的に使用するには十分なことはまだ分かっていません。 –

+0

また、ストリームがどのように作成されているかに基づいて、ルートが配列の場合は最も理にかなっています。さもなければ、ストリームの最後の項目は、データのように見えません。空のオブジェクトや配列も非常に奇妙です。私はその結果をどのように解釈するのか分かりません。 –