jsonshjq

Updating values in JSON array using jq


Using jq, I am trying to update the value of each object in an array, the new value calculated from the value of other keys in the same array, and returning the whole updated JSON.

Test data saved in "cardata.json":

{
    "data": {
        "cars": [
            {
                "type": "limo",
                "rating": null,
                "comfort": 1,
                "specs": {
                    "seats": 6,
                    "heat": true,
                    "color": "black"
                }
            },
            {
                "type": "sedan",
                "rating": null,
                "comfort": 2,
                "specs": {
                    "seats": 4,
                    "heat": true,
                    "color": "blue"
                }
            },
            {
                "type": "open",
                "rating": null,
                "comfort": 3,
                "specs": {
                    "seats": 2,
                    "heat": true,
                    "color": "red"
                }
            },
            {
                "type": "sport",
                "rating": null,
                "comfort": 5,
                "specs": {
                    "seats": 1,
                    "heat": false,
                    "color": "yellow"
                }
            }
        ]
    }
}

So this command

jq '( .data.cars | map(.rating = (if .specs.seats > 3 then "OK" else "Too small" end)) )' cardata.json

does the right thing, sort of, but only returns the updated cars object

[
  {
    "type": "limo",
    "rating": "OK",
    "comfort": 1,
    "specs": {
      "seats": 6,
      "heat": true,
      "color": "black"
    }
  },
  {
    "type": "sedan",
    "rating": "OK",
    "comfort": 2,
    "specs": {
      "seats": 4,
      "heat": true,
      "color": "blue"
    }
  },
  {
    "type": "open",
    "rating": "Too small",
    "comfort": 3,
    "specs": {
      "seats": 2,
      "heat": true,
      "color": "red"
    }
  },
  {
    "type": "sport",
    "rating": "Too small",
    "comfort": 5,
    "specs": {
      "seats": 1,
      "heat": false,
      "color": "yellow"
    }
  }
]

but I cannot get the whole JSON.

What do I do wrong?


Solution

  • You were very close. To update an object in-place, you can use |=:

    jq '
        .data.cars |= map(
          .rating =
            if .specs.seats > 3 then
              "OK"
            else
              "Too small"
            end
        )
    ' cardata.json
    

    See jq playground.

    Alternatively, using the array iterator .[] instead of map (h/t ikegami):

    jq '
        .data.cars[] |= (
          .rating =
            if .specs.seats > 3 then
              "OK"
            else
              "Too small"
            end
        )
    ' cardata.json
    

    (playground)