Home > Software design >  Append JSON from deep nested value to top level with jq
Append JSON from deep nested value to top level with jq

Time:11-02

Here is some sample data: https://gist.github.com/dmc2015/19fc41aa677ba02a3bc49c53057ce408

Every script I have below should work, but I don't know how to combine them. I need to do the following:

  • change a key name
  • be able to select specific keys to return, I don't need them all
  • be able to select and parse values
  • turn parsed values in to key value pairs and add them back in to the json

Change a key name

jq '.cards[] | select(.closed == false) | with_entries(if .key == "id" then .key = "trello_id" else . end) | .' data.json

returns:

{
  "trello_id": "1234",
  ...
  ..
}

Select specific keys to return

jq '.cards[] | with_entries(select([.key] | inside(["name", "description"]) ) ) | .' data.json

returns:

{
  "desc": "*Important Notes* ",
  "name": "Housing - Lawrence"
}

Query & Parse Values to create my own keys

jq '.cards[] |
.checklists[] | select(.name == "Acct Information") |
  .checkItems[] | select(.name | contains ("Location")) |
  .name | .'  data.json |
    cut -d ":" -f 1 |  sed 's/"//g' |  sed -e 's/\(.*\)/\L\1/' | sed -r 's/\s /_/g'

returns: location_address

jq '.cards[] | .checklists[] | select(.name == "Acct Information") |
.checkItems[] | select(.name | contains ("Location")) |
  .name | .'  data.json |
  cut -d ":" -f 2 |
    sed -e 's/\"//g' -e 's/*//g'

returns "123 Hopscotch Way"

I can do most parts individually but I am struggling to see a way to do it all in one query. This is something close to the end result that I want.


    [
      {
        "trello_id": "1234",
        "desc": "*Important Notes* ",
        "name": "Housing - Lawrence"
        "location_address": "123 Hopscotch Way"
      }
    ]

CodePudding user response:

The first thing you do is you extract certain the elements of .data, discarding the rest of the document. You tried to reclaim the document using ., but . just means the current node. It does nothing at all alone. It definitely doesn't recuperate the lost document.

You want |=. X |= Y returns the node that was passed to the expression (i.e. the whole document in your case) with the applied changes.

.data[] |= ( .  = { location_address: "123 Hopscotch Way" } )

Input:

{
   "version": 1.0,
   "data": [
      { "name": "abc" },
      { "name": "def" },
      { "name": "ghi" }
   ]
}

Output:

{
  "version": 1,
  "data": [
    {
      "name": "abc",
      "location_address": "123 Hopscotch Way"
    },
    {
      "name": "def",
      "location_address": "123 Hopscotch Way"
    },
    {
      "name": "ghi",
      "location_address": "123 Hopscotch Way"
    }
  ]
}

Demo on jqplay

CodePudding user response:

Could something like this be what you are looking for?

.cards | map(
  select(.closed == false) | {trello_id: .id, desc, name}   ([
    .checklists[] | select(.name == "Acct Information")
    | .checkItems[].name | select(contains("Location"))
    | capture("(?<key>[^:]*):\\s*(?<value>.*)")
    | .key |= (gsub("\\s "; "_") | ascii_downcase)
    | .value |= gsub("\\*"; "")
  ] | from_entries)
)
[
  {
    "trello_id": "1234",
    "desc": "*Important Notes* ",
    "name": "Housing - Lawrence",
    "location_address": "123 Hopscotch Way"
  }
]

Demo

  • Related