Reduce nested json (PowerDNS stats)

54 views Asked by At

I'm trying to improve on a jq reduce, but finding that some of the returned data is nested and the code I'm using breaks on that.

This is where I've got the jq code from: https://github.com/influxdata/telegraf/tree/master/plugins/inputs/powerdns_recursor

Taking tonumber off I get the following clipped output:

[...]
  "x-ourtime8-16": "0",
  "zone-disallowed-notify": "0",
  "response-by-qtype": [
    {
      "name": "A",
      "value": "8958"
    },
    {
      "name": "NS",
      "value": "6"
    },
[...]

The original code, with tonumber left in:

curl -s -H 'X-API-Key: <key>' http://127.0.0.1:8082/api/v1/servers/localhost/statistics | jq 'reduce .[] as $item ({}; . + { ($item.name): ($item.value|tonumber)})'

The output I'm after:

[...]
  "x-ourtime8-16": 0,
  "zone-disallowed-notify": 0,
  "response-by-qtype.A": 8958,
  "response-by-qtype.NS": 6,
[...]

I've spent some time Googling jq and nested input, but I don't want the index numbers this gave me in the names. I'm hoping a small tweak will do the trick.

2

There are 2 answers

1
Philippe On BEST ANSWER

To transform this input :

{
  "x-ourtime8-16": "0",
  "zone-disallowed-notify": "0",
  "response-by-qtype": [
    {
      "name": "A",
      "value": "8958"
    },
    {
      "name": "NS",
      "value": "6"
    }
  ]
}

You can run :

jq ' to_entries |
     map(if (.value | type) == "string"
         then .value |= tonumber
         else .key as $key | .value[] |
              .name  |= $key+"."+. |
              .value |= tonumber
         end
     ) | from_entries
' input.json

to get :

{
  "x-ourtime8-16": 0,
  "zone-disallowed-notify": 0,
  "response-by-qtype.A": 8958,
  "response-by-qtype.NS": 6
}
0
peak On

You can convert numeric strings to numbers using:

if type == "string" then . as $in | try tonumber catch $in else . end

As a post-processing step, you could use walk as a wrapper:

walk(if type == "string" then . as $in | try tonumber catch $in else . end)