jq conditional update an array element
Asked Answered
G

3

5

I want to conditionally update an element value based on the value of another element within the same array.

For example, I want to find name=="weather" and change checked from "true" to "false"

[
  {
    "originalSourceId": null,
    "sourceConnection": {
      "id": null,
      "version": null,
      "properties": [
        {
          "id": null,
          "version": null
        }
      ],
      "name": "POSTGRESQL",
      "businessName": null
    },
    "checked": true,
    "newlyAdded": false,
    "discoveredEntities": [
      {
        "name": "weather",
        "checked": true,
        "checkedBeforeEdit": false,
        "storeFieldsAsStrings": false
      },
      {
        "name": "weather_2",
        "checked": true,
        "checkedBeforeEdit": false,
        "storeFieldsAsStrings": false
      }
    ],
    "defaultLevel": "MANAGED"
  }
]

the checked element will update to "false" for the same object with name = "weather"

[
  {
    "originalSourceId": null,
    "sourceConnection": {
      "id": null,
      "version": null,
      "properties": [
        {
          "id": null,
          "version": null
        }
      ],
      "name": "POSTGRESQL",
      "businessName": null
    },
    "checked": true,
    "newlyAdded": false,
    "discoveredEntities": [
      {
        "name": "weather",
        "checked": false,
        "checkedBeforeEdit": false,
        "storeFieldsAsStrings": false
      },
      {
        "name": "weather_2",
        "checked": true,
        "checkedBeforeEdit": false,
        "storeFieldsAsStrings": false
      }
    ],
    "defaultLevel": "MANAGED"
  }
]
Giorgione answered 4/9, 2018 at 16:55 Comment(1)
I've tried jq . | jq '[.[].discoveredEntities[] | if (.name=="weather") then (.checked = "false") else . end]' ./test.json. But it is only return portion of it back with updated checked = false for weather. </pre>[ { "name": "weather", "checked": "false", "checkedBeforeEdit": false, "storeFieldsAsStrings": false }, { "name": "weather_2", "checked": true, "checkedBeforeEdit": false, "storeFieldsAsStrings": false } ]<code>Giorgione
G
4

Figured it out.

jq '[.[].discoveredEntities[] |= if (.name=="weather") then (.checked = "false") else . end]'\
    ./test.json
Giorgione answered 4/9, 2018 at 18:38 Comment(2)
You don't need the outer square brackets [], in this context, you're putting the results in an array. But since the body is just assignments, the initial input will always be returned. You'll end up with your original input updated, but in an array.Billingsgate
It would be more consistent with the remainder of the document to use the boolean value false rather than the string "false".Wagon
B
3

For these sorts of updates, it's easier to visualize if you think of it this way, locate the items you want to update first, then update them.

 (.[].discoveredEntities[] | select(.name == "weather").checked) = false
#[ locate the items to update                         ]
#                                                      [ update them   ]
Billingsgate answered 5/9, 2018 at 6:22 Comment(1)
While the update works, it has an unintended side effect of returning filtered results. Is there any way to include unmodified items to the result set?Hoard
W
0

Using map here yields a very straightforward if somewhat pedestrian solution:

map( .discoveredEntities |=
        map(if .name == "weather" then .checked = false else . end))

Note that it is evidently more appropriate to use false here rather than "false".

Wagon answered 7/9, 2018 at 18:3 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.