Как использовать jq, чтобы найти все пути к определенному ключу
В очень большой вложенной структуре json я пытаюсь найти все пути, заканчивающиеся на ключе.
например:
{
"A": {
"A1": {
"foo": {
"_": "_"
}
},
"A2": {
"_": "_"
}
},
"B": {
"B1": {}
},
"foo": {
"_": "_"
}
}
будет печатать что-то вроде: ["A","A1","foo"], ["foo"]
К сожалению, я не знаю, на каком уровне вложенности будут появляться ключи, поэтому я не смог разобраться с помощью простого выбора. Я сблизился с jq '[paths] | .[] | select(contains(["foo"]))'
, но вывод содержит все перестановки любого дерева, содержащего foo. выход: ["A", "A1", "foo"]["A", "A1", "foo", "_"]["foo"][ "foo", "_"]
Бонусные баллы, если бы я мог сохранить исходный формат структуры данных, но просто отфильтровать все пути, которые не содержат ключ (в этом случае вложенные деревья в "foo" не нужно было бы скрывать).
2 ответа
С вашим вкладом:
$ jq -c 'paths | select(.[-1] == "foo")'
["A","A1","foo"]
["foo"]
Бонусные очки:
(1) Если ваш JQ имеет tostream
:
$ jq 'fromstream(tostream| select(.[0]|index("foo")))'
Или еще лучше, так как ваш ввод велик, вы можете использовать потоковый парсер (jq -n --stream
) с этим фильтром:
fromstream( inputs|select( (.[0]|index("foo"))))
(2) Есть ли у вашего JQ tostream
:
. as $in
| reduce (paths(scalars) | select(index("foo"))) as $p
(null; setpath($p; $in|getpath($p))))
Во всех трех случаях вывод:
{
"A": {
"A1": {
"foo": {
"_": "_"
}
}
},
"foo": {
"_": "_"
}
}
У меня была такая же фундаментальная проблема.
С вводом (yaml), например:
developer:
android:
members:
- alice
- bob
oncall:
- bob
hr:
members:
- charlie
- doug
this:
is:
really:
deep:
nesting:
members:
- example deep nesting
Я хотел найти все произвольно вложенные группы и получить их участников.
Используя это:
yq . | # convert yaml to json using python-yq
jq '
. as $input | # Save the input for later
. | paths | # Get the list of paths
select(.[-1] | tostring | test("^(members|oncall|priv)$"; "ix")) | # Only find paths which end with members, oncall, and priv
. as $path | # save each path in the $path variable
( $input | getpath($path) ) as $members | # Get the value of each path from the original input
{
"key": ( $path | join("-") ), # The key is the join of all path keys
"value": $members # The value is the list of members
}
' |
jq -s 'from_entries' | # collect kv pairs into a full object using slurp
yq --sort-keys -y . # Convert back to yaml using python-yq
Я получаю такой вывод:
developer-android-members:
- alice
- bob
developer-android-oncall:
- bob
hr-members:
- charlie
- doug
this-is-really-deep-nesting-members:
- example deep nesting