jsonjq

How to recursively print the path of all keys in jq


I'd like to get a list of all paths available in a JSON document, just to get an idea of the layout of a big json document.

One liners preferred, of course a big jq/python program can do the trick.

Example:

$ jq -r 'short magic here' <<< '{"k1": {"k12": "v12"}, "k2": {"k21": {"k211": "v211"}}}'
k1
k1.k12
k2
k2.k21
k2.k21.k211

There are variations (not exactly duplicates) of this question like 'all paths matching a given pattern' or 'print paths plus value'. I'm asking just about the keys, all of them, and a short expression.

There is also third parties like gron that prints keys and values colorized.


Solution

  • Use jq -r 'paths | map(numbers |= "[\(.)]") | join(".")'.

    For example:

    $ jq -r 'paths | map(numbers |= "[\(.)]") | join(".")' <<< '{"k1": "v1", "k2": {"k21": "v21"}, "k3": {"k31": {"k311": "v311"}}, "k4": [{"k41": "v41"}, {"k42": "v42"}], "k5": {"0": "v50", "1": "v51"}}'
    k1
    k2
    k2.k21
    k3
    k3.k31
    k3.k31.k311
    k4
    k4.[0]
    k4.[0].k41
    k4.[1]
    k4.[1].k42
    k5
    k5.0
    k5.1
    

    A more succinct expression like paths | join(".") will render array indices and numeric object keys the same way. That might be not desirable.

    $ jq -r 'paths | join(".")' <<< '{"k1": "v1", "k2": {"k21": "v21"}, "k3": {"k31": {"k311": "v311"}}, "k4": [{"k41": "v41"}, {"k42": "v42"}], "k5": {"0": "v50", "1": "v51"}}'
    k1
    k2
    k2.k21
    k3
    k3.k31
    k3.k31.k311
    k4
    k4.0
    k4.0.k41
    k4.1
    k4.1.k42
    k5
    k5.0
    k5.1
    

    Credit for both solutions goes to @pmf.