Search code examples
jsonselectkeyjq

Using JQ to inject element at specific position based on conditions


Pulling my hair here, trying to use jq to parse and extend a JSON file and adding an element at a specific position based on a certain condition. Here is a sample file (also at https://jqplay.org/s/6cjmbnvrqu)

{
  "TopA": { "stuff": "here"},
  "TopB": {
    "C591AB7E": {
      "Type": "this",
      "Properties": {
        "lots": 1,
        "of": 2,
        "values" : 3
      }
    },
    "7E16765A": {
      "Type": "this",
      "Properties": {
        "lots": 4,
        "of": 5,
        "values" : 6
      }
    },
    "AAD76465": {
      "Type": "that",
      "Properties": {
        "lots": 7,
        "of": 8,
        "values" : 9
      }
    }
  }
}

The goal is to add an element to the Properties node of any TopB child where .Type == "that". And the kicker is that I need to put the child node's key into the new element value with an added prefix. So essentially I need the last element to look like this:

"AAD76465": {
  "Type": "that",
  "Properties": {
    "lots": 7,
    "of": 8,
    "values": 9,
    "newElement": "Prefix-AAD76465"
  }
}

I also need to retain the whole rest of the file (or a new file for that matter). So I don't need a query but really a jq call to manipulate the existing file. Parallel to TopB there could be other elements that I'd still need in the file. And no, I don't know, neither do I have control over the naming of the children of TopB. All I have is that my targets are nested children of TopB with .Type == "that". There can be multiple of those.

Thanks for looking.


Solution

  • If you get the path to where you will be adding the new field first, you can simply extract the parent key from that.

    reduce path(.TopB[] | select(.Type == "that") .Properties.newElement) as $p (.; setpath($p; "Prefix-\($p[1])"))
    

    Online demo