Using jq to parse and display multiple fields in a json serially

JsonJq

Json Problem Overview


I have this Json

{
    "users": [
        {
            "first": "Stevie",
            "last": "Wonder"
        },
        {
            "first": "Michael",
            "last": "Jackson"
        }
    ]
}

Using jq I'd like to display first and last name serially. Like so -

Stevie Wonder
Michael Jackson

This is how far I have gotten -

jq '.users[].first, .users[].last'

But it displays

"Stevie"
"Michael"
"Wonder"
"Jackson"

Notice the following:

  1. The double quotes that I do not want.
  2. The carriage return that I do not want.
  3. It's jumbled up. My query displays all the first names first, and then all the last names. However, I want first-last, first-last pair.

Json Solutions


Solution 1 - Json

I recommend using String Interpolation:

jq '.users[] | "\(.first) \(.last)"'

We are piping down the result of .users[] to generate the string ".first .last" using string interpolation. \(foo) syntax is used for string interpolation in jq. So, for the above example, it becomes "Stevie Wonder" (".users[].first .users[].second" working elementwise) and "Michael Jackson".

jq reference: String interpolation

Solution 2 - Json

You can use addition to concatenate strings.

> Strings are added by being joined into a larger string.

jq '.users[] | .first + " " + .last'

The above works when both first and last are string. If you are extracting different datatypes(number and string), then we need to convert to equivalent types. Referring to solution on this question. For example.

jq '.users[] | .first + " " + (.number|tostring)'

Solution 3 - Json

jq '.users[]|.first,.last' | paste - -

Solution 4 - Json

In addition to what others have suggested, I think that two options are worth mentioning.

$ cat file.json | jq -r '.users[] | [.first, .last] | @tsv'
Stevie  Wonder
Michael Jackson
cat file.json | jq -r '.users[] | [.first, .last] | @csv'
"Stevie","Wonder"
"Michael","Jackson"

The first expression, .users[], unnests the objects from the outer-most array as in the code given in the question. The next expression, [.first, .last], creates a new array of the values for each input object, and the final expression uses the built-in functions @tsv and @csv to print all input arrays as tab-separated and comma-seperated values, respectively.

Similarly, it is possible to construct JSON values again, which is interesting if you just want to keep a subset of the fields:

$ cat file.json | jq -c '.users[] | {first}'
{"first":"Stevie"}
{"first":"Michael"}

Solution 5 - Json

my approach will be (your json example is not well formed.. guess thats only a sample)

jq '.Front[] | [.Name,.Out,.In,.Groups] | join("|")'  front.json  > output.txt

returns something like this

"new.domain.com-80|8.8.8.8|192.168.2.2:80|192.168.3.29:80 192.168.3.30:80"
"new.domain.com -443|8.8.8.8|192.168.2.2:443|192.168.3.29:443 192.168.3.30:443"

and grep the output with regular expression.

Solution 6 - Json

While both of the above answers work well if key,value are strings, I had a situation to append a string and integer (jq errors using the above expressions)

Requirement: To construct a url out below json

pradeep@seleniumframework>curl http://192.168.99.103:8500/v1/catalog/service/apache-443 | jq .[0]
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   251  100   251    0     0   155k      0 --:--:-- --:--:-- --:--:--  245k
{
  "Node": "myconsul",
  "Address": "192.168.99.103",
  "ServiceID": "4ce41e90ede4:compassionate_wozniak:443",
  "ServiceName": "apache-443",
  "ServiceTags": [],
  "ServiceAddress": "",
  "ServicePort": 1443,
  "ServiceEnableTagOverride": false,
  "CreateIndex": 45,
  "ModifyIndex": 45
}

Solution:

curl http://192.168.99.103:8500/v1/catalog/service/apache-443 |
jq '.[0] | "http://" + .Address + ":" + "\(.ServicePort)"'

Solution 7 - Json

This will produce an array of names

> jq '[ .users[] | (.first + " " + .last) ]' ~/test.json

[  "Stevie Wonder",  "Michael Jackson"]

Solution 8 - Json

I got pretty close to what I wanted by doing something like this

cat my.json | jq '.my.prefix[] | .primary_key + ":", (.sub.prefix[] | "    - " + .sub_key)' | tr -d '"' 

The output of which is close enough to yaml for me to usually import it into other tools without much problem. (I am still looking for a way to basicallt export a subset of the input json)

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionSanView Question on Stackoverflow
Solution 1 - JsonEric HartfordView Answer on Stackoverflow
Solution 2 - JsonabrahamView Answer on Stackoverflow
Solution 3 - JsonoptmanView Answer on Stackoverflow
Solution 4 - Jsoningomueller.netView Answer on Stackoverflow
Solution 5 - JsonGanesh ChandrasekaranView Answer on Stackoverflow
Solution 6 - JsonmachzqcqView Answer on Stackoverflow
Solution 7 - JsonTinyRoyView Answer on Stackoverflow
Solution 8 - JsonThorSummonerView Answer on Stackoverflow