Объединить результаты jq-запроса в один массив - PullRequest
1 голос
/ 06 июля 2019

У меня есть входной файл, который имеет независимые объекты JSON (т.е. не массив), и я хочу отфильтровать несколько полей из каждого из них и создать массив с результирующими элементами.В основном это список операторов журнала в формате JSON.

Я использую jq для этого, и он отлично работает, за исключением того, что я не могу объединить все результирующие объекты в один массив.

Входные данные выглядят примерно так:

{"name":"myname", "environment":"staging", "email":"email1@example.com", "time":"2017-04-02T05:00:00.046Z"}
{"name":"myname", "environment":"staging", "email":"email2@example.com", "time":"2017-02-02T05:00:00.046Z"}
...
{"name":"myname", "environment":"staging", "email":"email3@example.com", "time":"2017-10-02T05:00:00.046Z"}
{"name":"myothername", "environment":"staging", "time":"2017-10-02T05:00:00.046Z"}

(обратите внимание, что последняя запись не имеет поля email, и поэтому она вернет значение null, если не отфильтровано)

Из этого списка объектов я хотел бы получить только поля email и time и игнорировать остальные, поэтому я использовал следующий запрос jq:

jq '{email: (.email | values), time: (.time | values)}' input.json

Обратите внимание, что я использую фильтр values, потому что сообщения журнала смешаны, поэтому не все объекты json имеют поле email, поэтому я их игнорирую.

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

Т.е. я получаю что-то вроде

{"email":"email1@example.com", "time":"2017-04-02T05:00:00.046Z"}
{"email":"email2@example.com", "time":"2017-02-02T05:00:00.046Z"}
...
{"email":"email3@example.com", "time":"2017-10-02T05:00:00.046Z"}

И я хотел бы, чтобы это было похоже:

[
    {"email":"email1@example.com", "time":"2017-04-02T05:00:00.046Z"},
    {"email":"email2@example.com", "time":"2017-02-02T05:00:00.046Z"},
    ...,
    {"email":"email3@example.com", "time":"2017-10-02T05:00:00.046Z"}
]

Я пробовал несколько разных вещей, но обычно получаю ошибку Cannot index array with string "email", которая говорит мне, что я делаючто-то не так с операциями с массивами.

Я попытался обернуть запрос в map(), то есть map({.userEmail, .time}), попытался отбросить данные с помощью -s и попытался использовать операторы |+ и |=,

Я также пытался заключить запрос в скобки массива, как [{email: (.email|values), time:.time }], но я получаю те же самые результирующие объекты, за исключением того, что каждый из них заключен в массив сам по себе, т.е.

[{"email":"email1@example.com", "time":"2017-04-02T05:00:00.046Z"}]
[{"email":"email2@example.com", "time":"2017-02-02T05:00:00.046Z"}]
...
[{"email":"email3@example.com", "time":"2017-10-02T05:00:00.046Z"}]

Кажется, что это, вероятно, легко сделать, или, по крайней мере, обычная операция, но я не могу найти правильный запрос.

Каков правильный способ объединения результатов запроса в массив, если входные данные не являются массивом?

Ответы [ 2 ]

1 голос
/ 06 июля 2019

Еще лучше ...

  1. На основе ваших данных выборки ваш базовый фильтр может быть упрощен до {email, time}

  2. Как правило, лучше избегать «прихлебывания» ввода (например, для экономии памяти). В вашем случае это можно сделать, используя inputs с параметром командной строки -n.

Собираем все вместе:

jq -n '[inputs | {email, time }]' input.json

Если есть какие-то входные данные, которые вы хотите отфильтровать, вы можете использовать select, например,

jq -n '[inputs | select(.email) | {email, time } ]' input.json
0 голосов
/ 06 июля 2019

После прочтения я нашел нужный мне результат, представляющий собой комбинацию оператора slurp и map.

Я понял, что запрос

jq -s 'map({email: (.email|values), time:.time })' input.json

будет читать все входные элементы как массив , а затем как в соответствии с определением map () :

Для любого фильтра x, map (x) запустит этот фильтр для каждого элемента входного массива и вернет выходные данные в новом массиве

Итак, оба вместе дали мне результат, который мне был нужен.

...