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

Counting instances of a value using jq

I’m trying to use jq to parse the output of some tool. Specifically I’m looking for a count of various HTTP status codes in the output json. I.e. something like

jq -c '. | <filter>' test.json
{200: 1, 301: 1, 403: 1}

from the following input json

#test.json
[
    {
        "content-length": 45,
        "path": "/foo",
        "redirect": null,
        "status": 200
    },
    {
        "content-length": 40,
        "path": "/bar",
        "redirect": null,
        "status": 301
    },
    {
        "content-length": 1150,
        "path": "/baz",
        "redirect": null,
        "status": 403
    }
]

I could just loop through in bash with something like

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

$ for i in 200 301 403; do echo -n $i "    "; jq '[.[] | select(.status | tostring =="'$i'")] | length' test.json ; done
200     1
301     1
403     1

but that seems inefficient. Trying to loop in jq feels like the better way to go, but the actual syntax to do it is a bit beyond me. I haven’t had any luck finding exapmples, and I haven’t had any luck trying to interpret the man pages

$ jq '[200, 301, 403] as $s | {$s: [.[] | select(.status == $s)] | length}' test.json 
jq: error: syntax error, unexpected ':', expecting '}' (Unix shell quoting issues?) at <top-level>, line 1:
[200, 301, 403] as $s | {$s: [.[] | select(.status == $s)] | length}                           
jq: error: May need parentheses around object key expression at <top-level>, line 1:
[200, 301, 403] as $s | {$s: [.[] | select(.status == $s)] | length}                         
jq: 2 compile errors

The python equivalent to what I want to do, in case that’s clearer, is

import json
from collections import Counter
dat = json.load(open("test.json"))
print(Counter(d["status"] for d in dat))'
# Counter({200: 1, 301: 1, 403: 1})

>Solution :

This works:

reduce .[] as $row ({}; .[$row.status | tostring] += 1)

The trick is realizing that you never really wanted select in the first place, that’s a relic of the "bash is looping and deciding what status I’m looking for" way of working. tostring is because jq objects can’t have numbers as keys, only strings.

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