Traversing with jq/yq

Viewed 132

I have a data file similar to the one as below

{
  "user01": {
    "name": "User01 Name",
    "age": "20",
    "sex": "male",
    "state": "CA",
    "zip": "92012"
  },
  "user02": {
    "name": "User02 Name",
    "age": "22",
    "sex": "female"
  },
  "user03": {
    "age": "24",
    "sex": "male",
    "zip": "92412"
  },
  "user04": {
    "name": "User05 Name",
    "age": "30",
    "sex": "female",
    "state": "UT",
    "zip": "96232"
  }
}

I would like to get output like this

"user01" "name" "User01 Name"
"user01" "age" "20"
"user01" "sex" "male"
"user01" "state" "CA"
"user01" "zip" "92012"
"user02" "name" "User02 Name"
"user02" "age" "22"
"user02" "sex" "female"
"user03" "age" "24"
"user03" "sex" "male"
"user03" "zip" "92412"
"user04" "name" "User05 Name"
"user04" "age" "30"
"user04" "sex" "female"
"user04" "state" "UT"
"user04" "zip" "96232"

I'm not able to figure out how to keep the top level key, print the key value pair as each of them is processed. Thanks for your help.

1 Answers
jq -r '
  to_entries[] |                  # replace items with {"key": ..., "value": ...}
    .key as $username |           # store top-level key in $username
    .value |                      # later code operates only on value
    to_entries[] |                # break top-level value into key/value pairs
    ([$username, .key, .value] |  # create list w/ desired output fields
     map(tojson) |                # encode those fields as literal JSON
     join(" "))                   # ...and separate those JSON fields with spaces
'

Concatenated onto a single line, this looks like:

jq -r 'to_entries[] | .key as $username | .value | to_entries[] | ([$username, .key, .value] | map(tojson) | join(" "))'

@peak also kindly pointed out a terser alternative that avoids the need for $username:

jq -r '
  to_entries[] |      # Replace items with {"key":..., "value": ...}
    [.key]+(          # Prepend key to results of next group:
      .value |        #   ...creating that group by starting with the value
      to_entries[] |  #   ...then splitting it further into key/value pairs
      [.key, .value]  #   ...then putting key and value into a list
    ) |
    map(tojson) |     # encode the results of the above as JSON strings
    join(" ")         # ...and then separate those strings with spaces.
'
Related