Search code examples
jsonjq

Changing parent value, when child meet specific conditions


I'm currently struggling with some jq, hope somebody can help. Given is the following JSON structure:

[
    {
        "id": "100",
        "input": "ChecklistState",
        "value": "-",
        "sub": [
            {
                "id": "110",
                "input": "Text",
                "value": "foo",
                "sub": []
            },
            {
                "id": "120",
                "input": "ChecklistState",
                "value": "OK",
                "sub": []
            },
            {
                "id": "130",
                "input": "ChecklistState",
                "value": "OK",
                "sub": []
            },
            {
                "id": "140",
                "input": "ChecklistState",
                "value": "OK",
                "sub": []
            }
        ]
    }
]

I need a filter, that changes "value" to "OK" of the parent ("id": "100"), when every child in "sub" with "input" value "Text" has no empty "value" and every "input" value "ChecklistState" has value "OK". ( -> 110 not empty, 120, 130 and 140 "OK")

A generally usable filter (checking for the input) would be great, but I also wouldn't mind a solution, where I check for every child-ID individually.

I've tried accessing the values of the childs with select(.sub[]?.id=="xxx").value and concatenating that in an if-then-else-end-Block, however the results was, that the conditions seemed not to work.

Please note: due to software requirements, I need to use jq v1.5


Solution

  • I need a filter, that changes the value of the parent (ID 100) to OK, when 110s value is not empty and 120, 130 and 140s value is OK. Please note: due to software requirements, I need to use jq v1.5

    Here's one way using from_entries to generate an index object from the .sub array that can be queried:

    map(                                                        # for all items
      if .sub | map(.key = .id) | from_entries                  # create an index
        | [."110" != "OK", .["120","130","140"] == "OK"] | all  # match condition
      then .value = "OK"
      else .
      end
    )
    

    Demo


    I need a filter, that changes the value of the parent (ID 100) to OK, when every child with input type "Text" has no empty value and every input type "ChecklistState" has value OK. ( -> 110 not empty, 120, 130 and 140 "OK")

    In this case, I'd apply all directly onto the .sub array with the modified conditions.

    map(
      if .sub | all(
        .input == "Text" and .value != "" or
        .input == "ChecklistState" and .value == "OK"
      )
      then .value = "OK"
      else .
      end
    )
    

    Demo


    Output:

    [
      {
        "id": "100",
        "input": "ChecklistState",
        "value": "OK",
        "sub": [
          {
            "id": "110",
            "input": "Text",
            "value": "foo",
            "sub": []
          },
          {
            "id": "120",
            "input": "ChecklistState",
            "value": "OK",
            "sub": []
          },
          {
            "id": "130",
            "input": "ChecklistState",
            "value": "OK",
            "sub": []
          },
          {
            "id": "140",
            "input": "ChecklistState",
            "value": "OK",
            "sub": []
          }
        ]
      }
    ]