How to get key names from JSON using jq - json

curl http://testhost.test.com:8080/application/app/version | jq '.version' | jq '.[]'
The above command outputs only the values as below:
"madireddy#test.com"
"2323"
"test"
"02-03-2014-13:41"
"application"
How can I get the key names instead like the below:
email
versionID
context
date
versionName

To get the keys in the order they appear in the original JSON use:
jq 'keys_unsorted' file.json
If you want the keys sorted alphanumerically, you can use:
jq 'keys' file.json
Complete example
$ cat file.json
{ "Created-By" : "Apache Maven", "Build-Number" : "", "Archiver-Version" : "Plexus Archiver", "Build-Id" : "", "Build-Tag" : "", "Built-By" : "cporter"}
$ jq 'keys_unsorted' file.json
[
"Created-By",
"Build-Number",
"Archiver-Version",
"Build-Id",
"Build-Tag",
"Built-By"
]
$ jq 'keys' file.json
[
"Archiver-Version",
"Build-Id",
"Build-Number",
"Build-Tag",
"Built-By",
"Created-By"
]

To get the keys on a deeper node in a JSON:
echo '{"data": "1", "user": { "name": 2, "phone": 3 } }' | jq '.user | keys[]'
"name"
"phone"

You need to use jq 'keys[]'. For example:
echo '{"example1" : 1, "example2" : 2, "example3" : 3}' | jq 'keys[]'
Will output a line separated list:
"example1"
"example2"
"example3"

In combination with the above answer, you want to ask jq for raw output, so your last filter should be eg.:
cat input.json | jq -r 'keys'
From jq help:
-r output raw strings, not JSON texts;

To print keys on one line as csv:
echo '{"b":"2","a":"1"}' | jq -r 'keys | [ .[] | tostring ] | #csv'
Output:
"a","b"
For csv completeness ... to print values on one line as csv:
echo '{"b":"2","a":"1"}' | jq -rS . | jq -r '. | [ .[] | tostring ] | #csv'
Output:
"1","2"

If your input is an array of objects,
[
{
"a01" : { "name" : "A", "user" : "B" }
},
{
"a02" : { "name" : "C", "user" : "D" }
}
]
try with:
jq '.[] | keys[]'

Oddly enough, the accepted answer doesn’t actually answer the Q exactly, so for reference, here is a solution that does:
$ jq -r 'keys_unsorted[]' file.json

echo '{"ab": 1, "cd": 2}' | jq -r 'keys[]' prints all keys one key per line without quotes.
ab
cd

Here's another way of getting a Bash array with the example JSON given by #anubhava in his answer:
arr=($(jq --raw-output 'keys_unsorted | #sh' file.json))
echo ${arr[0]} # 'Archiver-Version'
echo ${arr[1]} # 'Build-Id'
echo ${arr[2]} # 'Build-Jdk'

Related

How to extract values from a json object with spaces using jq

I have the below JSON string with multiple JSON objects. I would like to extract just the id and name from each object and print it.
{
"users": [
{
"id": "1",
"name": "John Wick",
"location": "USA"
},
{
"id": "2",
"name": "Walter White",
"location": "USA"
}
]
}
I am using the below code to extract the id and name using 'jq'
for key in $(jq -c '.users | .[]' sample.json); do
id=$(jq -r '.id' <<< "$key");
name=$(jq -r '.name' <<< "$key")
echo $id $name
done
But I am getting parsing errors like below. Can someone help me with this?
parse error: Unfinished string at EOF at line 2, column 0
I tried replacing spaces with a combination of special chars and replace again special chars with spaces. It worked for me but I need a better solution than this.
You can use the csv or tsv features of jq - lots of great examples in the man page!
man jq
Try this:
jq -r '.users[] | [.id , .name] | #csv' sample.json
Example output:
$ jq -r '.users[] | [.id , .name] | #csv' sample.json
"1","John Wick"
"2","Walter White"
Or using string interpolation:
$ jq -r '.users[] | [.id, .name] | "\(.[0]) \(.[1])"' sample.json
1 John Wick
2 Walter White
Using 2 read's to capture the values, we can let JQ loop over the objects, and output the id and name. :
#!/bin/bash
jq -r -c '.users[] | .id, .name' /tmp/input3 | while read -r id && read -r name; do
echo -e "ID: ${id}\t Name: ${name}"
done
Output:
ID: 1 Name: John Wick
ID: 2 Name: Walter White

Skip or Ignore non-existing key with to_entries in jq

I'm trying to create a massive CSV file converted from each *.json file. This snippet works until it faces the file that doesn't have the key (hobby).
Original
{
"name": "bob",
"hobby": [
"baseball",
"baseketball"
]
}
jq snippet
cat *.json | jq '.name as $n | .hobby | to_entries[] | [ $n, .value]'
It works
[][]... is a pre-format when creating CSV with jq
[
"bob",
"baseball"
]
[
"bob",
"baseketball"
]
https://jqplay.org/s/L-SmqiN-jw
However if the .hobby key doesn't exist it fails miserably.
jq: error (at <stdin>:6): null (null) has no keys
exit status 5
https://jqplay.org/s/gapUv1Tpmb
I tried to use if block but it seems not correct. How can we do such a thing either
return [] (empty array)
skip jq excution for the current working file with this problem and go to the next
One of many possibilities would be to use try:
.name as $n | .hobby | try to_entries[] | [ $n, .value]
try EXP is equivalent to try EXP catch empty.
Enter the following:
{
"name": "bob",
"hobby": [
"baseball",
"baseketball"
]
}
$ cat file | jq -c "{name,hobby:.hobby[]}|[.[]]"
["bob","baseball"]
["bob","baseketball"]

How to map a list of key/values to a space separated list of keyValue=valueValue entries in jq?

How can I transform this output:
$ jq -s '.[0] * .[1] * .[2] | to_entries' a.json b.json c.json
[
{
"key" : "SimpleNumber",
"value" : "123"
},
{
"key" : "SimpleString",
"value" : "Hello"
},
{
"key" : "ComplexString",
"value" : "Hello World"
}
]
to:
1)
"SimpleNumber=123" "SimpleString=Hello" "ComplexString=Hello World"
and
2)
SimpleNumber="123" SimpleString="Hello" ComplexString="Hello World"
String interpolation combined with join():
jq --raw-output 'map("\"\(join("="))\"") | join(" ")'
to generate
"SimpleNumber=123" "SimpleString=Hello" "ComplexString=Hello World"
Try it online
Or to it 'by hand' to quote only the value:
jq --raw-output 'map("\(.key)=\"\(.value)\"") | join(" ")'
SimpleNumber="123" SimpleString="Hello" ComplexString="Hello World"
Try it online
Use string interpolation and put the quotes as you see fit:
around whole items
jq -r 'map("\"\(.key)=\(.value)\"") | join(" ")'
"SimpleNumber=123" "SimpleString=Hello" "ComplexString=Hello World"
Demo
just around the "value"
jq -r 'map("\(.key)=\"\(.value)\"") | join(" ")'
SimpleNumber="123" SimpleString="Hello" ComplexString="Hello World"
Demo

BASH/Linux - How do you parse JSON with jq when array doesn't have any keys? [duplicate]

curl http://testhost.test.com:8080/application/app/version | jq '.version' | jq '.[]'
The above command outputs only the values as below:
"madireddy#test.com"
"2323"
"test"
"02-03-2014-13:41"
"application"
How can I get the key names instead like the below:
email
versionID
context
date
versionName
To get the keys in the order they appear in the original JSON use:
jq 'keys_unsorted' file.json
If you want the keys sorted alphanumerically, you can use:
jq 'keys' file.json
Complete example
$ cat file.json
{ "Created-By" : "Apache Maven", "Build-Number" : "", "Archiver-Version" : "Plexus Archiver", "Build-Id" : "", "Build-Tag" : "", "Built-By" : "cporter"}
$ jq 'keys_unsorted' file.json
[
"Created-By",
"Build-Number",
"Archiver-Version",
"Build-Id",
"Build-Tag",
"Built-By"
]
$ jq 'keys' file.json
[
"Archiver-Version",
"Build-Id",
"Build-Number",
"Build-Tag",
"Built-By",
"Created-By"
]
To get the keys on a deeper node in a JSON:
echo '{"data": "1", "user": { "name": 2, "phone": 3 } }' | jq '.user | keys[]'
"name"
"phone"
You need to use jq 'keys[]'. For example:
echo '{"example1" : 1, "example2" : 2, "example3" : 3}' | jq 'keys[]'
Will output a line separated list:
"example1"
"example2"
"example3"
In combination with the above answer, you want to ask jq for raw output, so your last filter should be eg.:
cat input.json | jq -r 'keys'
From jq help:
-r output raw strings, not JSON texts;
To print keys on one line as csv:
echo '{"b":"2","a":"1"}' | jq -r 'keys | [ .[] | tostring ] | #csv'
Output:
"a","b"
For csv completeness ... to print values on one line as csv:
echo '{"b":"2","a":"1"}' | jq -rS . | jq -r '. | [ .[] | tostring ] | #csv'
Output:
"1","2"
If your input is an array of objects,
[
{
"a01" : { "name" : "A", "user" : "B" }
},
{
"a02" : { "name" : "C", "user" : "D" }
}
]
try with:
jq '.[] | keys[]'
Oddly enough, the accepted answer doesn’t actually answer the Q exactly, so for reference, here is a solution that does:
$ jq -r 'keys_unsorted[]' file.json
echo '{"ab": 1, "cd": 2}' | jq -r 'keys[]' prints all keys one key per line without quotes.
ab
cd
Here's another way of getting a Bash array with the example JSON given by #anubhava in his answer:
arr=($(jq --raw-output 'keys_unsorted | #sh' file.json))
echo ${arr[0]} # 'Archiver-Version'
echo ${arr[1]} # 'Build-Id'
echo ${arr[2]} # 'Build-Jdk'

How to capture values from JSON parent and sub-parent parameter using JQ?

I have this below JSON file which I need to capture using JQ, but so far I only manage to capture the parent parameter (SUBSCRIBER_ID), but unable to capture the sub-parent parameter which is "Offer".
Need your guys help on providing a correct JQ filter to capture both "SUBSCRIBER_ID" and "Offer" value.
JSON
{"Data1": [
{"Data2": {
"SUBSCRIBER_ID" : "999050280010099",
"MSISDN" : "999050280010099",
"EMAIL" : "john#email.com",
"OFFERS" : [
{
"Offer" : 12344,
"EffectiveDate" : "1488787236",
"ExpiryDate" : "4070869200"
} ],
"IsGroup" : "false",
}}
]}
My JQ Filter which is not working
'.Data1 | .[] | .Data2 | to_entries | map(.value) | #csv' -r
Expected output:
SUBSCRIBER_ID,Offer
999050280010099,12344
You can try this jq:
jq -r '.Data1|.[]|.Data2|[.SUBSCRIBER_ID, .OFFERS[].Offer]|#csv' file > out.csv
(OR) As suggested by #peak,
jq -r '.Data1[].Data2|[.SUBSCRIBER_ID, .OFFERS[].Offer]|#csv' file
Another one method:
jq -r '.[]|.[]|map([.SUBSCRIBER_ID, .OFFERS[].Offer])|.[]|#csv' file
Input:
$ cat file.json
{
"Data1": [
{
"Data2": {
"SUBSCRIBER_ID": "999050280010099",
"MSISDN": "999050280010099",
"EMAIL": "john#email.com",
"OFFERS": [
{
"Offer": 12344,
"EffectiveDate": "1488787236",
"ExpiryDate": "4070869200"
}
],
"IsGroup": "false"
}
}
]
}
Test:
$ jq -r '.Data1|.[]|.Data2|[.SUBSCRIBER_ID, .OFFERS[].Offer]|#csv' file.json
"999050280010099",12344
$ jq -r '.[]|.[]|map([.SUBSCRIBER_ID, .OFFERS[].Offer])|.[]|#csv' file.json
"999050280010099",12344