
Допустим, у меня есть JSON следующего вида:
{
"key1": {
"keyA": "1",
"keyB": "null",
"keyC": "null"
},
"key2": {
"keyA": "null",
"keyB": "3",
"keyC": "null"
}
}
Я хотел бы найти способ исключить все ключи со значением null
в моем JSON. Поэтому результат будет следующим:
{
"key1": {
"keyA": "1"
},
"key2": {
"keyB": "3"
}
}
Я знаю, что могу исключить определенные ключи по их именам, используя jq
, например cat myjson.json | jq 'del(.[]|.keyA)'
, это сотрет все мои keyA
ключи внутри json, но я хочу исключить ключи в соответствии с их значениями... Как я могу исключить все ключи по значению, "null"
используя jq
?
решение1
del(..|select(. == "null"))
Здесь используетсяоператор рекурсивного спуска..
иselect
функциядля поиска всех местоположений в любом месте объекта со значениями, равными , "null"
и присваивает их del
. select
оценивает логическое выражение, чтобы решить, включать ли конкретное значение или нет, при этом ..
присваивает ему каждое отдельное значение в дереве и del
принимает любое выражение, которое создает местоположения, что и делает этот метод. (демо)
Вы можете использовать path
функцию, чтобы проверить, что она находит:
path(..|select(. == "null"))
и отладить то, что он думает, что вы пытаетесь удалить в первую очередь.выходпредставляет собой массив ключей, по которым необходимо рекурсивно пройти для достижения значения, и поэтому последний элемент массива — это ключ, который фактически будет удален.
Вы также можете использовать update-assignment |= empty
в jq 1.6 и выше (в более ранних версиях он молча терпит неудачу). Вы можете найти это более понятным, а можете и нет: (..|select(. == "null")) |= empty
(демо) удаляет те же самые ключи.
Если ваши значения — это true null
s, а не строка "null"
, вы можете использовать nulls
встроенную функцию вместо всего select
: del(..|nulls)
.
Если ваши значения — истинные нулиивы используетеджк 1.5(текущая версия во многих дистрибутивах), вам нужно будет использовать recurse(.[]?; true)
вместо ..
. Это потому, что нулевые значения специально исключены из ..
(потому чтоэто определяется какrecurse
, которыйопределяется как recurse(.[]?)
, который определяется как recurse(.[]?; . != null)
). Это поведение изменилось на (более полезное) в версии 1.6, хотядокументацияне изменилось, чтопохоже, это ошибка документации.
решение2
Предположим, что вы хотите проверить значения на 2-м уровне:
jq 'del(.[][] | select(. == "null"))' file
Это удалит все пары ключ-значение на 2-м уровне сверху, где значение представляет собой литеральную строку null
.
Учитывая документ, заданный в вопросе, это дает ожидаемый результат.
Используя версию jq
новее 1.5, вы также можете просто обновить данные до тех битов, которые не имеют значения null
:
jq '.[][] |= select(. != "null")' file