jq
jq позволяет работать с json из консоли. На jqplay.org можно дебажить скрипт, выдаёт строку для вставки в command line.
Далее в примерах будет код на jq. Для вызова использовать
Примеры запросов
-
построчное чтение и обработка файла, где каждая строка — корректная json строка
-
-c,--compact-output— вывод результата jq в одну строку -
вывод одного поля
-
фильтрация списка json-объектов по значению поля
-
собрать новый объект. Можно использовать краткое определение (shorter notation)
Пояснения по работе jq
jq читает входные данные как набор json, разделённых пробелами. json может быть как объект, там и коллекция объектов.
Пример файла, где каждая запись — объект:
```json lines {"id": 1, "name": "userName 1"} {"id": 2, "name": "userName 2"} {"id": 3, "name": "userName 3"}</details>
<details>
<summary>Пример файла, где каждая запись — массив объектов:</summary>
```json lines
[{"id": 1, "productName": "product 1"}, {"id": 11, "productName": "product 2"}]
[{"id": 2, "productName": "product 1"}, {"id": 22, "productName": "product 2"}]
[{"id": 3, "productName": "product 1"}, {"id": 33, "productName": "product 2"}]
К каждой записи jq применяет фильтр. Соответственно надо учитывать, какой тип будет на входе — объект или массив.
Самый простой фильтр — . — он просто отправляет данные дальше.
Следующий фильтр .foo — получает значение по ключу и возвращает его. Такой вариант сработает, если на входе объект, а не массив. Если ключа не существует - бросит ошибку
Фильтр .[] — возвращает все элементы массива. Если надо применить фильтр к каждому значению массива — надо использовать оператор |
# в файле каждая строка - json массив объектов
# [{"id": 123, "name": "value 1"}, {"id": 123, "name": "value 2"}, {"id": 123, "name": "value 3"}]
.[] | .name
Формирование объектов и массивов на выходе
Чтоб на выходе был массив или объект — используются конструкции jq '[]' и jq '{}'
Например, если надо собрать новый объект по каждой записи, где каждая запись — массив объектов, то делаем так:
- кажудю запись читаем как массив
- далее через пайп направляем на конструктор объекта с указанием имени поля
fieldNewNameи фильтром.name, который вытащит значение из очередного объекта
Фильтрация данных
Для фильтрации данных используется функция select. Она не меняет данные. Она либо отправляет текущие данные дальше, либо не делает ничего.
Пример фильтрации входящих данных, а потом формирования новых объектов:
# если каждая запись - объект
select(.name == "value") | { auto: .name }
# если каждая запись - массив объектов
.[] | select(.name == "value") | { auto: .name }
select поддерживает логические операторы:
Определение типа данных
С помощью функции type можно запросить тип очередной записи.
По каждой записи она выведет "object" либо "array":
Различные примеры
Работа с логами, содержащими json текст
На входе:
[2023-06-30 11:11:11] INFO []: Sending: {"Items":[{"ID":"11","Value":1},{"ID":"12","Value":1},{"ID":"13","Value":1}],"Password":"Pass"}
[2023-06-30 12:12:12] INFO []: Sending: {"Items":[{"ID":"22","Value":1}],"Password":"Pass"}
[2023-06-30 21:21:21] INFO []: Sending: {"Items":[{"ID":"33","Value":1}],"Password":"Pass"}
Необходимо извлечь дату и добавить её внутрь json, вернуть новый объект
ltrimstr("[") | split("] INFO []: Sending: ") | .[0] as $date | .[1] | fromjson | .Items[].date = $date | .Items[]
С помощью split разбиваем строку в массив.
С помощью Variable / Symbolic Binding Operator: ... as $identifier сохраняем дату в переменную.
С помощью fromjson перегоняем json в объект. Далее расширяем нужные нам объекты с помощью переменной.
Вызов: