Извлечь данные из JSON-документа, встроенного в другой JSON-документ.

Вопрос или проблема

У меня есть JSON-документ, который встраивает другой JSON-документ. Мне нужно извлечь данные из встроенного документа, но я не очень хорошо разбираюсь в JSON или jq.

Вот мой входной файл (guard.json):

{
  "_index": "test-2021.06.02",
  "_type": "servrd",
  "_id": "ZWUxMDU5MjItOGY2MC00MGI5LWJhZTEtODRhYWQ1YTZhOGIy",
  "_version": 1,
  "_score": null,
  "_source": {
    "stream": "stdout",
    "time": "2021-10-02T03:13:52.496705721Z",
    "docker": {
      "container_id": "392923402349320329432h3432k4kj32kfks9s9sdfksdfjkdsjfsh3939322342"
    },
    "kubernetes": {
      "container_name": "test",
      "namespace_name": "dev",
      "pod_name": "test-dev-v004-9s885",
      "container_image": "localhost:80/pg/test:1.19.0",
      "container_image_id": "docker-pullable://localhost:80/pg/test@sha256:2sfdsfsfsfsfdsr3wrewrewc235e728ad1b29baf5af3dfad30c7706e5eda38b6109",
      "pod_id": "ssfsfds-dsfdsfs-fs-sfsfs-sfdsfsdfsewrw",
      "host": "test-jup-node008",
      "labels": {
        "app": "test",
        "cluster": "test-dev",
        "load-balancer-test-dev": "true",
        "stack": "dev",
        "app_kubernetes_io/managed-by": "spinnaker",
        "app_kubernetes_io/name": "test",
        "moniker_spinnaker_io/sequence": "4"
      },
      "min_url": "https://100.400.0.22:443/api",
      "namespace_id": "jajdjsdf-dfse-dsf-koksls-sksjf030292",
      "namespace_labels": {
        "name": "dev"
      }
    },
    "elapsedTime": 39013,
    "message": "TransactionLog",
    "membersId": "TEST_0233203203_030202020303",
    "payload": "{\"serviceId\":\"00343\",\"AccessKey\":\"testdfsolpGS\",\"trackID\":\"KOLPSLSLSLL99029283\",\"membersId\":\"TEST_0233203203_030202020303\",\"shopperInfo\":{\"emailAddress\":\"[email protected]\",\"ipAddress\":\"localhost\"},\"parkid\":{\"parkssID\":\"carrier-park\"},\"cartinfo\":{\"checkType\":\"preorder\",\"detailsmetis\":\"card\",\"currency\":\"US\",\"grosscount\":\"10\",\"reedeem\":\".00\",\"Discount\":\".00\",\"tokenvalue\":{\"token\":\"11102020392023920920393993\",\"Bin\":\"00000\",\"digit\":\"0000\",\"expirationDate\":\"202509\",\"price\":\"10\"}},\"cartdetails\":[{\"dones\":[{\"donesnames\":\"test\",\"price\":\"003\",\"quan\":\"1\"}]}]}",
    "requestDate": "2021-10-02T03:13:12.541207804Z",
    "requestId": "12321321wes-sfsfdsf-snnm79887-029299",
    "finalToClient": "{\"finalType\":\"ok\",\"evaluationMessage\":\"Accept\",\"subMessage\":\"testcallled\",\"score\":0}",
    "serviceId": 00343,
    "timestamp": "2021-10-02T03:13:51.951+00:00",
    "@timestamp": "2021-10-02T03:13:52.621643399+00:00"
  },
  "fields": {
    "@timestamp": [
      "2021-10-02T03:13:52.621Z"
    ],
    "requestDate": [
      "2021-10-02T03:13:12.541Z"
    ],
    "timestamp": [
      "2021-10-02T03:13:51.951Z"
    ]
  },
  "highlight": {
    "kubernetes.labels.app": [
      "@kibana-highlighted-field@test@/kibana-highlighted-field@"
    ]
  },
  "sort": [
    1654139632621
  ]
}

Мне нужен вывод в формате CSV, похожий на этот:

serviceId, trackID, currency, grosscount
00343,KOLPSLSLSLL99029283,US,10

Ваш вопрос касается извлечения определенной информации, хранящейся в JSON-документе, встроенном как строка JSON (._source.payload) в другой JSON-документ.

Чтобы получить JSON-документ с вашими данными, сначала нужно извлечь документ из его родительского документа:

jq '._source.payload | fromjson' guard.json

Учитывая пример в вашем вопросе, это даст что-то вроде

{
  "serviceId": "00343",
  "AccessKey": "testdfsolpGS",
  "trackID": "KOLPSLSLSLL99029283",
  "membersId": "TEST_0233203203_030202020303",
  "shopperInfo": {
    "emailAddress": "[email protected]",
    "ipAddress": "localhost"
  },
  "parkid": {
    "parkssID": "carrier-park"
  },
  "cartinfo": {
    "checkType": "preorder",
    "detailsmetis": "card",
    "currency": "US",
    "grosscount": "10",
    "reedeem": ".00",
    "Discount": ".00",
    "tokenvalue": {
      "token": "11102020392023920920393993",
      "Bin": "00000",
      "digit": "0000",
      "expirationDate": "202509",
      "price": "10"
    }
  },
  "cartdetails": [
    {
      "dones": [
        {
          "donesnames": "test",
          "price": "003",
          "quan": "1"
        }
      ]
    }
  ]
}

Из этого вы хотели бы выбрать .serviceId, .trackID, .cartinfo.currency и .cartinfo.grosscount в формате CSV с заголовками.

Можно сделать это так:

jq -r '._source.payload | fromjson |
    [ "serviceId", "trackID", "currency", "grosscount" ],
    [ .serviceId, .trackID, .cartinfo.currency, .cartinfo.grosscount ] |
    @csv' guard.json

Первый массив — это просто массив строк заголовков, в то время как второй извлекает данные для каждого столбца. Эти два массива затем форматируются и выводятся в формате CSV с использованием оператора @csv.

С данными в вопросе это дало бы

"serviceId","trackID","currency","grosscount"
"00343","KOLPSLSLSLL99029283","US","10"

Дополнительные материалы (октябрь 2022):

Использование jq для извлечения встроенной полезной нагрузки, затем использование Miller для создания результирующего CSV:

$ jq '._source.payload | fromjson' file | mlr --j2c cut -f serviceId,trackID,cartinfo:currency,cartinfo:grosscount then label serviceId,trackID,currency,grosscount
serviceId,trackID,currency,grosscount
00343,KOLPSLSLSLL99029283,US,10

Обратите внимание, что Miller не добавляет кавычки к полям CSV, если кавычки не требуются.

Ответ или решение

Извлечение данных из документа JSON, встроенного в другой документ JSON, может стать сложной задачей, особенно для тех, кто не знаком с этим форматом данных. JSON (JavaScript Object Notation) — это текстовый формат обмена данными, удобно читаемый как человеком, так и машиной, распространенный в веб-разработке и различных других сферах. Чтобы эффективно работать с JSON в рамках определенной задачи, существуют инструменты и библиотеки, такие как jq, специализированные для обработки и извлечения данных из JSON-объектов.

Теория

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

Инструмент jq — это программа командной строки для обработки данных JSON. Она позволяет извлекать и преобразовывать данные с использованием мощного языка запросов. Одной из особенностей jq является возможность работы с встроенными JSON-документами через функцию fromjson, которая позволяет преобразовать строку в объект JSON для дальнейшего извлечения данных.

Пример

Рассмотрим пример JSON-файла guard.json, в котором содержится уровень вложенности в поле _source.payload:

{
  "_index": "test-2021.06.02",
  "_type": "servrd",
  ...
  "_source": {
    ...
    "payload": "{\"serviceId\":\"00343\",\"AccessKey\":\"testdfsolpGS\",\"trackID\":\"KOLPSLSLSLL99029283\",\"membersId\":\"TEST_0233203203_030202020303\",\"shopperInfo\":{\"emailAddress\":\"[email protected]\",\"ipAddress\":\"localhost\"},\"cartinfo\":{\"currency\":\"US\",\"grosscount\":\"10\"}}",
    ...
  }
}

Здесь payload содержит JSON как строку. Для извлечения данных понадобится выполнить следующие шаги:

  1. Преобразовать строку, содержащую JSON, назад в объект JSON, используя jq с функцией fromjson.
  2. Указать ключи для извлечения интересующих данных.

Применение

Теперь, когда мы понимаем, как работает структура, применим jq для извлечения и преобразования данных в формат CSV. Это удобно для импорта в электронные таблицы или другие системы анализа. Рассмотрим следующий пример команды:

jq -r '._source.payload | fromjson | 
    ["serviceId", "trackID", "currency", "grosscount"], 
    [ .serviceId, .trackID, .cartinfo.currency, .cartinfo.grosscount ] | 
    @csv' guard.json

Этот запрос jq выполняет следующее:

  • ._source.payload | fromjson: извлекает строковое поле payload и преобразует его обратно в JSON-объект.
  • Два массива: первый содержит заголовки для CSV, второй содержит значения, сопоставленные из JSON-объекта.
  • @csv: формирует результат в виде CSV-строки, который включает в себя строки заголовка и данных.

Результат выполнения команды будет выглядеть так:

"serviceId","trackID","currency","grosscount"
"00343","KOLPSLSLSLL99029283","US","10"

Эта CSV-строка может быть экспортирована в различные системы для дальнейшего анализа или обработки.

Заключение

Понимание структуры JSON и использование специализированных инструментов, таких как jq, позволяют эффективно извлекать и преобразовывать данные из сложных JSON-документов. В данном случае, задача была облегчена пониманием того, как работать с вложенными и строковыми JSON-документами, применяя подходящие методы и утилиты для получения необходимых данных в удобном формате. Активное освоение таких инструментов открывает широкие возможности для автоматизации задач обработки данных, что критически важно в современных ИТ-процессах.

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

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