Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

updating fields matching condition under not nice path

I need very often update conditionally some fields in subtree to which leads ugly path. I kinda can solve it, but it’s very ugly solution, I’d like to know if there is smth better.

Sample input:

{
  "very": {
    "un-fortunate": {
      "p-a-t-h": {
        "first": {
          "veryDeepSubTree": {},
          "someValue": 1
        },
        "second": {
          "veryDeepSubTree": {},
          "someValue": 2
        },
        "third": {
          "veryDeepSubTree": {},
          "someValue": 3
        }
      }
    }
  }
}

desired output: say that I would like to add 10 to someValue. Suppose that I cannot use recursive descent, for example I want to update only odd someValue.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

I can write solution like this:

jq '.very|=(.["un-fortunate"]|=(.["p-a-t-h"] |=(  . as $root| reduce keys[] as $k ({}; . + {($k): ($root|.[$k]|.someValue|=(.+10))})      )))'

but it’s hard to read and write (matching brackets)…

explained motivation, based on my (mis?)understanding:

  • iiuc I need to bracket every non-trivial right operand of |= , especially if there are more of them, otherwise it does not compile
  • I cannot express longer path than just one field at a time, if path is sufficiently ugly
  • there isn’t other way(maybe except foreach, which I cannot understand) to update all items of object, than using reduce to copy all into new updating value, and update each part in update clause of reduce command

questions:

  • is there some better way of expressing unfortunate path from tree root?
  • can I express it somehow easier than via using this reduce over keys, and putting field update logic into accumulator part of reduce command?
  • if you are writing commands into shell, how do you do it so that you can easily edit it + it’s readable?

>Solution :

You could use the array value iterator [] in combination with the (arithmetic) update-assignment operator |=.

To update all someValues:

.very."un-fortunate"."p-a-t-h"[].someValue |= . + 10

or

.very."un-fortunate"."p-a-t-h"[].someValue += 10

To update only someValues which are odd, filter through select and don’t forget to parenthesize the LHS):

(.very."un-fortunate"."p-a-t-h"[].someValue | select(. % 2 != 0)) += 10

Output:

{
  "very": {
    "un-fortunate": {
      "p-a-t-h": {
        "first": {
          "veryDeepSubTree": {},
          "someValue": 11
        },
        "second": {
          "veryDeepSubTree": {},
          "someValue": 2
        },
        "third": {
          "veryDeepSubTree": {},
          "someValue": 13
        }
      }
    }
  }
}

But even recursive descent would work, you just have to make sure to only select the correct values:

(.. | objects | .someValue | values | select(. % 2 != 0)) += 10

or

(.. | .someValue? | values | select(. % 2 != 0)) += 10

Output is identical to above.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading