Search code examples
jsonjqpowerdns

Reduce nested json (PowerDNS stats)


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.


Solution

  • 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
    }