0

I need from this: (example)

{
  "jobs": [
      {},
      {}
    ],
  "services": {
    "service-1": {
      "version": "master"
    },
    "service-2": {
      "foo": true,
      "version": "master"
    },
    "service-3": {
      "bar": "baz"
    }
  }
}

Make this:

{
  "services": {
    "service-1": {
      "version": "master"
    },
    "service-2": {
      "version": "master"
    }
  }
}

So delete all except .services.*.version. Help please, can't handle it with my knowledge of the JQ.

peak
  • 105,803
  • 17
  • 152
  • 177
Tw1ce
  • 3
  • 1

2 Answers2

1

If you wish to differentiate between "version" being absent or null:

{services}
| .services |= map_values(select(has("version")) | {version} )
peak
  • 105,803
  • 17
  • 152
  • 177
1

Translating your expression .services.*.version quite generically, you could use tostream as follows:

reduce (tostream
        | select(length==2 and
                 (.[0] | (.[0] == "services" and
                          .[-1] == "version")))) as $pv (null;
    setpath($pv[0]; $pv[1]) )

Using jq's streaming parser

To reduce memory requirements, you could modify the above solution to use jq's streaming parser, either with reduce as above, or with fromstream:

jq -n --stream -f program.jq input.json

where program.jq contains:

fromstream(inputs
    | select( if length == 2
              then .[0] | (.[0] == "services" and
                           .[-1] == "version")
              else . end ) )

.services.*.version.*

Interpreting .services.*.version more broadly so as not to require the terminal component of the path to be .version, simply replace .[-1] == "version" with:

index("version")

in the above.

peak
  • 105,803
  • 17
  • 152
  • 177