Home > database >  How to refer to parent object in jq walk?
How to refer to parent object in jq walk?

Time:03-02

I have some json that I want to add to based on a walk. A simple example of the json I have is below:

{
  "valueSource": "memory",
  "dataType": "Boolean",
  "alarms": [
    {
      "setpointA": 1.0,
      "name": "Alarm",
      "priority": "Diagnostic",
      "ackMode": "Auto",
    }
  ],
  "name": "Test Alarm",
  "value": false,
  "tagType": "AtomicTag"
}

I want to add to each object in the "alarms" key's array the following key:

{
   "bindType": "Tag",
   "value": "[.]<parent.name>.Name"
}

where <parent.name> is "Test Alarm" in this example which is the parent-of-the-alarm-array-item's "name" key.

I've gotten this jq filter so far that adds the object, but the value key value is wrong (it's getting the alarm array item's name instead of its parent's name):

walk( if type == "object" and .setpointA then .label = {"bindType":"Tag", "value": "[.]\(.name).Name"} else . end)

Essentially I want this:

{
  "valueSource": "memory",
  "dataType": "Boolean",
  "alarms": [
    {
      "setpointA": 1.0,
      "name": "Alarm",
      "priority": "Diagnostic",
      "ackMode": "Auto",
      "label": {
        "bindType": "Tag",
        "value": "[.]Test Alarm.Name"
      }
    }
  ],
  "name": "Test Alarm",
  "value": false,
  "tagType": "AtomicTag"
}

Here is my jqplay below. It has the final result in the JSON section, where the Result should match this but doesn't at the moment. https://jqplay.org/s/-qHFIWolrD

CodePudding user response:

You cannot reference to parent, you have to save the reference in a variable beforehand, and descend with having access to that variable.

.tags[] |= (
  .name as $name
  | # rest of your code using $name
    walk(
      if type == "object" and .setpointA
      then .label = {"bindType":"Tag", "value": "[.]\($name).Name"}
      else . end
    )
)

Demo

As you happen to know that the objects are located in the .alarms array, you could also just iterate over the items, select only those matching the condition and then assign to their .label whatever you want (including $name)

.tags[] |= (
  .name as $name
  | (.alarms[] | select(has("setpointA"))).label = {
      bindType: "Tag", value: "[.]\($name).Name"
    }
)

Demo

CodePudding user response:

As jq does not allow you to refer to parent object, you need to work on parent level :

jq 'walk(if type == "object" and .alarms and ( .alarms | arrays )
         then (.alarms[] | select(.setpointA)).label =
                    { bindType: "Tag", value: "[.]\(.name).Name"}
         else . end
    )' data.json
  • Related