Как исключить все ключи с определенным значением внутри JSON с помощью jq?

Как исключить все ключи с определенным значением внутри JSON с помощью jq?

Допустим, у меня есть 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 nulls, а не строка "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

Связанный контент