Вопрос или проблема
Я начинаю с json, который выглядит так:
{
"object": "list",
"data": [
{
"id": "in_1HW85aFGUwFHXzvl8wJbW7V7",
"object": "invoice",
"account_country": "US",
"customer_name": "clientOne",
"date": 1601244686,
"livemode": true,
"metadata": {},
"paid": true,
"status": "paid",
"total": 49500
},
{
"id": "in_1HJlIZFGUwFHXzvlWqhegRkf",
"object": "invoice",
"account_country": "US",
"customer_name": "clientTwo",
"date": 1598297143,
"livemode": true,
"metadata": {},
"paid": true,
"status": "paid",
"total": 51000
},
{
"id": "in_1HJkg5FGUwFHXzvlYp2uC63C",
"object": "invoice",
"account_country": "US",
"customer_name": "clientThree",
"date": 1598294757,
"livemode": true,
"metadata": {},
"paid": true,
"status": "paid",
"total": 57000
},
{
"id": "in_1H8B0pFGUwFHXzvlU6nrOm6I",
"object": "invoice",
"account_country": "US",
"customer_name": "clientThree",
"date": 1595536051,
"livemode": true,
"metadata": {},
"paid": true,
"status": "paid",
"total": 20000
}
],
"has_more": true,
"url": "/v1/invoices"
}
Если я сделаю
cat sample.json | jq -C '.data[] | {invoice_id: .id, date: .date | strftime("%Y-%m-%d"), amount: .total} | .amount = "$" + (.amount/100|tostring)'
Я смогу успешно упорядочить это (фактические данные гораздо более многословны, сотни строк, которые нужно убрать), и это даст мне:
{
"invoice_id": "in_1HW85aFGUwFHXzvl8wJbW7V7",
"date": "2020-09-27",
"amount": "$495"
}
{
"invoice_id": "in_1HJlIZFGUwFHXzvlWqhegRkf",
"date": "2020-08-24",
"amount": "$510"
}
{
"invoice_id": "in_1HJkg5FGUwFHXzvlYp2uC63C",
"date": "2020-08-24",
"amount": "$570"
}
{
"invoice_id": "in_1H8B0pFGUwFHXzvlU6nrOm6I",
"date": "2020-07-23",
"amount": "$200"
}
Но порядок неправильный. Я хочу отсортировать по полю даты, чтобы самый последний элемент отображался внизу.
Я попробовал все возможные неправильные вещи. Как мне применить sort_by(.date)
к этому? Я продолжаю получать ошибки cannot index string with string "date"
(и много других, но в основном эту).
из man jq
sort, sort_by(path_expression)
Функция sort сортирует свой вход, который должен быть массивом.
В общем, чтобы вызвать отдельную команду jq
, вы должны использовать -s
, --slurp
, что сделает эти последовательные объекты массивом, и тогда вы сможете отсортировать его по ключу.
... | jq -s 'sort_by(.date)'
Теперь, если у вас уже есть выбор, и вы хотите, чтобы результат был массивом, тогда я думаю, что обернув это все в скобки, вы сделаете это:
jq '[ <some_existing_selection> ] | sort_by(.date)' file.json
пример
Для json, с которого вы начинаете, предположим, что изначально вы делаете что-то подобное (создавая последовательность объектов):
jq '.data[] | {id: .id, date: .date}' file.json
вам нужно обернуть весь выбор jq в скобки, чтобы сделать это массивом:
jq '[.data[] | {id: .id, date: .date}]' file.json
и теперь этот массив можно отсортировать:
jq '[.data[] | {id: .id, date: .date}] | sort_by(.date)' file.json
Ответ или решение
Чтобы отсортировать поток JSON-объектов по значению поля с использованием jq
, вам нужно следовать нескольким шагам. Давайте разберем процесс на вашем примере.
В начале у вас есть JSON с такой структурой:
{
"object": "list",
"data": [
{
"id": "in_1HW85aFGUwFHXzvl8wJbW7V7",
"object": "invoice",
"account_country": "US",
"customer_name": "clientOne",
"date": 1601244686,
"livemode": true,
"metadata": {},
"paid": true,
"status": "paid",
"total": 49500
},
{
"id": "in_1HJlIZFGUwFHXzvlWqhegRkf",
"object": "invoice",
"account_country": "US",
"customer_name": "clientTwo",
"date": 1598297143,
"livemode": true,
"metadata": {},
"paid": true,
"status": "paid",
"total": 51000
},
{
"id": "in_1HJkg5FGUwFHXzvlYp2uC63C",
"object": "invoice",
"account_country": "US",
"customer_name": "clientThree",
"date": 1598294757,
"livemode": true,
"metadata": {},
"paid": true,
"status": "paid",
"total": 57000
},
{
"id": "in_1H8B0pFGUwFHXzvlU6nrOm6I",
"object": "invoice",
"account_country": "US",
"customer_name": "clientThree",
"date": 1595536051,
"livemode": true,
"metadata": {},
"paid": true,
"status": "paid",
"total": 20000
}
],
"has_more": true,
"url": "/v1/invoices"
}
Вы хотите создать более компактный вывод из этих данных и отсортировать результаты по дате. Ваш текущий запрос выглядит так:
cat sample.json | jq -C '.data[] | {invoice_id: .id, date: .date | strftime("%Y-%m-%d"), amount: .total} | .amount = "$" + (.amount/100|tostring)'
Для решения вашей задачи вам нужно сначала обернуть результат в квадратные скобки, чтобы создать массив. Затем вы сможете отсортировать этот массив по полю date
. Итоговый запрос будет выглядеть следующим образом:
cat sample.json | jq '[.data[] | {invoice_id: .id, date: (.date | strftime("%Y-%m-%d")), amount: .total}] | sort_by(.date) | .[] | .amount = "$" + (.amount/100 | tostring)'
Пояснение шагов:
-
Создание массива: Путем добавления квадратных скобок
[...]
к вашему текущему запросу, вы создаете массив объектов, что позволяет использовать функциюsort_by
. -
Сортировка: Используйте
sort_by(.date)
, чтобы отсортировать массив по дате. Это гарантирует, что объекты будут отсортированы от старшей даты к более новой. -
Форматирование результата: После сортировки используйте
.[]
для извлечения и отображения отдельных объектов. Это позволяет выводить результаты каждый в своей строке. -
Форматирование суммы: Используйте
amount = "$" + (.amount / 100 | tostring)
для форматирования количества в нужный вид.
Таким образом, результат будет упорядочен по дате с правильно отформатированными полями.