Как отсортировать поток 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)'

Я смогу успешно упорядочить это (фактические данные гораздо более многословны, сотни строк, которые нужно убрать), и это даст мне:

{
  "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)'

Пояснение шагов:

  1. Создание массива: Путем добавления квадратных скобок [...] к вашему текущему запросу, вы создаете массив объектов, что позволяет использовать функцию sort_by.

  2. Сортировка: Используйте sort_by(.date), чтобы отсортировать массив по дате. Это гарантирует, что объекты будут отсортированы от старшей даты к более новой.

  3. Форматирование результата: После сортировки используйте .[] для извлечения и отображения отдельных объектов. Это позволяет выводить результаты каждый в своей строке.

  4. Форматирование суммы: Используйте amount = "$" + (.amount / 100 | tostring) для форматирования количества в нужный вид.

Таким образом, результат будет упорядочен по дате с правильно отформатированными полями.

Оцените материал
Добавить комментарий

Капча загружается...