Home > Enterprise >  JSON transformation -jq
JSON transformation -jq

Time:11-10

I am looking to transform a json response from an API call. I came across 'jq' and experimented with it, but it kept getting out of hand; was unable to get the desired output.

Sample Input JSON:

{
    "realtime": {
        "status": {
            "name": "realtime",
            "link": {
                "state": "RUNNING",
                "link_id": "09-1"
            },
            "items": [
                {
                    "id": 0,
                    "state": "RUNNING",
                    "link_id": "09-1"
                },
                {
                    "id": 1,
                    "state": "STOPPED",
                    "link_id": "09-1"
                }
            ],
            "doc": "origin"
        }
    },
    "cmx": {
        "status": {
            "name": "cmx",
            "link": {
                "state": "RUNNING",
                "link_id": "09-1"
            },
            "items": [
                {
                    "id": 0,
                    "state": "FAILED",
                    "link_id": "09-1",
                    "log": "ErrorMsg"
                }
            ],
            "doc": "origin"
        }
    }
}

Expected JSON Output:

{
    "realtime.0": {
        "name": "realtime",
        "state": "RUNNING",
        "url": "/link/realtime/",
        "item": 0,
        "item_state": "RUNNING",
        "item_url": "/links/realtime/items/0/"
    },
    "realtime.1": {
        "name": "realtime",
        "state": "RUNNING",
        "url": "/link/realtime/",
        "item": 1,
        "item_state": "STOPPED",
        "item_url": "/links/realtime/items/1/"x
    },
    "cmx.0": {
        "name": "cmx",
        "state": "RUNNING",
        "url": "/links/cmx/",
        "item": 0,
        "item_state": "FAILED",
        "item_url": "/links/cmx/items/0/",
        "log": "ErrorMsg"
    }
}

The best I got was with command below: .[]|.status | .name as $name |.link.state as $state| .items[] | {$name, $state,items:[.]}| del(.items[].link_id)

Which resulted in below (not even close):

{
  "name": "realtime",
  "state": "RUNNING",
  "items": [
    {
      "id": 0,
      "state": "RUNNING"
    }
  ]
}
{
  "name": "realtime",
  "state": "RUNNING",
  "items": [
    {
      "id": 1,
      "state": "STOPPED"
    }
  ]
}
{
  "name": "cms",
  "state": "RUNNING",
  "items": [
    {
      "id": 0,
      "state": "FAILED",
      "log": "Error"
    }
  ]
}

Appreciate the help. Also, it will very helpful in understanding the solution if an explanation to the steps / filters applied is given.

Thanks!!

CodePudding user response:

Here's one straightforward way using with_entries, which lets you manipulate the .key and .value fields for each item. Here, we store (iterate over) the items of the .status.items array in a variable, and piece together all the fields needed, either from the current .value (context) or from the current $item (variable).

with_entries(
  .value.status.items[] as $item
  | .key  = ".\($item.id)"
  | .value |= {
      name: .status.name,
      state: .status.link.state,
      url: "/link/\(.status.name)/",
      item: $item.id,
      item_state: $item.state,
      item_url: "/link/\(.status.name)/items/\($item.id)/",
      log: $item.log
  }
)
{
  "realtime.0": {
    "name": "realtime",
    "state": "RUNNING",
    "url": "/link/realtime/",
    "item": 0,
    "item_state": "RUNNING",
    "item_url": "/link/realtime/items/0/",
    "log": null
  },
  "realtime.1": {
    "name": "realtime",
    "state": "RUNNING",
    "url": "/link/realtime/",
    "item": 1,
    "item_state": "STOPPED",
    "item_url": "/link/realtime/items/1/",
    "log": null
  },
  "cmx.0": {
    "name": "cmx",
    "state": "RUNNING",
    "url": "/link/cmx/",
    "item": 0,
    "item_state": "FAILED",
    "item_url": "/link/cmx/items/0/",
    "log": "ErrorMsg"
  }
}

Demo

  • Related