2015-04-08 2 views
5

Учитывая входную строку json из массива, возвращаем объект только с элементами, имеющими ключи в исходном объекте и в массиве ввода.jq: выбор подмножества ключей от объекта

У меня есть решение, но я думаю, что он не изящный ({($k):$input[$k]} чувствует себя особенно неуклюжим ...) и что это шанс для меня узнать.

jq -n '{"1":"a","2":"b","3":"c"}' \ 
    | jq --arg keys '["1","3","4"]' \ 
    '. as $input 
    | ($keys | fromjson) 
    | map(. as $k 
      | $input 
      | select(has($k)) 
      | {($k):$input[$k]} 
     ) 
    | add' 

Любые идеи, как их очистить?

Я чувствую, что Extracting selected properties from a nested JSON object with jq - хорошее начальное место, но я не могу заставить его работать.

+1

Из документации, из которой я мог бы использовать(), в элементе rhs оператора ==, можно было выбрать 'select (.key == (" 1 "," 3 "," 4 ")) ' – Jon

ответ

7

Вы можете использовать этот фильтр:

with_entries(
    select(
     .key == ($keys | fromjson[]) 
    ) 
) 
0

Вот некоторые дополнительные разъяснения

Для ввода объекта {"key1":1, "key2":2, "key3":3} Я хотел бы удалить все ключи, которые не входят в набор требуемых ключей ["key1","key3","key4"]

jq -n --argjson desired_keys '["key1","key3","key4"]' \ 
     --argjson input '{"key1":1, "key2":2, "key3":3}' \ 
    ' $input 
    | with_entries(
      select(
       .key == ($desired_keys[]) 
     ) 
     )' 

with_entries преобразует {"key1":1, "key2":2, "key3":3} в следующий массив пары значений ключа s и отображает инструкцию select в массиве, а затем возвращает результирующий массив обратно в объект.

Вот внутренний объект в заявлении with_entries.

[ 
    { 
    "key": "key1", 
    "value": 1 
    }, 
    { 
    "key": "key2", 
    "value": 2 
    }, 
    { 
    "key": "key3", 
    "value": 3 
    } 
] 

мы можем выбрать ключи из этого массива, соответствующие нашим критериям.

Здесь происходит волшебство ... вот посмотрите, что происходит в середине этой команды. Следующая команда принимает расширенный массив значений и превращает их в список объектов, которые мы можем выбрать.

jq -cn '{"key":"key1","value":1}, {"key":"key2","value":2}, {"key":"key3","value":3} 
     | select(.key == ("key1", "key3", "key4"))' 

Это даст следующий результат

{"key":"key1","value":1} 
{"key":"key3","value":3} 

с помощью команды записи могут быть немного сложнее, но его легко запомнить, что требуется фильтр и определяется следующим образом

def with_entries(f): to_entries|map(f)|from_entries; 

Это то же самое, что и

def with_entries(f): [to_entries[] | f] | from_entries; 

Другая часть вопроса, который смущает людей, состоит из нескольких совпадений в правой части поля ==

Рассмотрим следующую команду. Мы видим, что выход представляет собой внешнее производство всех левых списков и списков правой руки.

Если этот предикат находится в операторе select, мы сохраняем ввод, когда предикат является истинным. Обратите внимание, что вы также можете дублировать входные данные.

jq -cn '1,2,3| select(. == (1,1,3))' 
1 
1 
3 
1

ответ Джеффа есть несколько ненужной неэффективность, оба из которых рассмотрены в следующем, в предположении, что --argjson keys используется вместо --arg keys:

with_entries(select(.key as $k | $keys | index($k))) 
+1

эта умный. избегает прохождения через весь внешний продукт входных ключей и желаемых клавиш. – Jon

2

решения с внутренней проверкой:

jq 'with_entries(select([.key] | inside(["key1", "key2"])))' 
0

внутренний оператор работает большую часть времени; Однако, я только что нашел внутри оператор побочный эффект, иногда выбранные клавиши не требуется, предположим, что вход { "key1": val1, "key2": val2, "key12": val12 } и выберите, inside(["key12"]) он выберет и "key1" и "key12"

использовать оператор, если необходимо точное совпадение: как это подберет .key2 и .key12 только

jq 'with_entries(select(.key | in({"key2":1, "key12":1})))' 

, потому что в операторе проверяет ключ от объекта только (или индекса exists? из массива), здесь он должен быть записан в синтаксисе объектов, с заданными ключами в качестве ключей, но значения не имеют значения; использование в операторе не является идеальным вариантом для этой цели, я хотел бы видеть Javascript ES6 включает обратную версию API, чтобы быть реализован в виде JQ встроен

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/includes

jq 'with_entries(select(.key | included(["key2", "key12"])))' 

проверить элемент .key является included? из массива

+0

Разве это не было отредактировано для вашего другого ответа? –

+0

, но могу ли я получить два ответа на одну и ту же тему? просто потому, что есть два разных подхода: – user5672998

+0

Вы можете, но обычно вы хотите поставить оговорки в один и тот же ответ, который предлагает его, поэтому никто не должен читать весь Q + A, прежде чем принимать решение о подходящем подходе. И довольно похожие подходы часто можно объединить в один ответ. –

Смежные вопросы