Listing all keys of a nested object with jq - json

I want to list the keys of a nested object of my document.
For example, I want the keys in the "a" object: "a1", "b1"
The sample document:
{
"a": {
"a1": "hello",
"a2": "world"
},
"b": {
"b1": "bonjour",
"b2": "monde"
}
}
I know I can use keys, but it seems to work only for the first level object: cat my.json | jq keys will output a, b.
So far I chain two calls with jq but I wonder if we can do it in one call ?
cat my.json | jq .a | jq keys --> a1, b1

Ok I've just find out in a single call :
cat my.json | jq '.a|keys'
a1, b1
Or even as #Inian suggested without the cat
jq '.a|keys' my.json
a1, b1

Related

Extract value inside a matching block using JQ in a nested array [duplicate]

I have the following json file:
{
"FOO": {
"name": "Donald",
"location": "Stockholm"
},
"BAR": {
"name": "Walt",
"location": "Stockholm"
},
"BAZ": {
"name": "Jack",
"location": "Whereever"
}
}
I am using jq and want to get the "name" elements of the objects where 'location' is 'Stockholm'.
I know I can get all names by
cat json | jq .[] | jq ."name"
"Jack"
"Walt"
"Donald"
But I can't figure out how to print only certain objects, given the value of a sub key (here: "location" : "Stockholm").
Adapted from this post on Processing JSON with jq, you can use the select(bool) like this:
$ jq '.[] | select(.location=="Stockholm")' json
{
"location": "Stockholm",
"name": "Walt"
}
{
"location": "Stockholm",
"name": "Donald"
}
To obtain a stream of just the names:
$ jq '.[] | select(.location=="Stockholm") | .name' json
produces:
"Donald"
"Walt"
To obtain a stream of corresponding (key name, "name" attribute) pairs, consider:
$ jq -c 'to_entries[]
| select (.value.location == "Stockholm")
| [.key, .value.name]' json
Output:
["FOO","Donald"]
["BAR","Walt"]
I had a similar related question: What if you wanted the original object format back (with key names, e.g. FOO, BAR)?
Jq provides to_entries and from_entries to convert between objects and key-value pair arrays. That along with map around the select
These functions convert between an object and an array of key-value
pairs. If to_entries is passed an object, then for each k: v entry in
the input, the output array includes {"key": k, "value": v}.
from_entries does the opposite conversion, and with_entries(foo) is a
shorthand for to_entries | map(foo) | from_entries, useful for doing
some operation to all keys and values of an object. from_entries
accepts key, Key, name, Name, value and Value as keys.
jq15 < json 'to_entries | map(select(.value.location=="Stockholm")) | from_entries'
{
"FOO": {
"name": "Donald",
"location": "Stockholm"
},
"BAR": {
"name": "Walt",
"location": "Stockholm"
}
}
Using the with_entries shorthand, this becomes:
jq15 < json 'with_entries(select(.value.location=="Stockholm"))'
{
"FOO": {
"name": "Donald",
"location": "Stockholm"
},
"BAR": {
"name": "Walt",
"location": "Stockholm"
}
}
Just try this one as a full copy paste in the shell and you will grasp it.
# pass the multiline string to the jq, use the jq to
# select the attribute named "card_id"
# ONLY if its neighbour attribute
# named "card_id_type" has the "card_id_type-01" value.
# jq -r means give me ONLY the value of the jq query no quotes aka raw
cat << EOF | \
jq -r '.[]| select (.card_id_type == "card_id_type-01")|.card_id'
[
{ "card_id": "id-00", "card_id_type": "card_id_type-00"},
{ "card_id": "id-01", "card_id_type": "card_id_type-01"},
{ "card_id": "id-02", "card_id_type": "card_id_type-02"}
]
EOF
# this ^^^ MUST start first on the line - no whitespace there !!!
# outputs:
# id-01
or with an aws cli command
# list my vpcs or
# list the values of the tags which names are "Name"
aws ec2 describe-vpcs | jq -r '.| .Vpcs[].Tags[]
|select (.Key == "Name") | .Value'|sort -nr
Note that you could move up and down in the hierarchy both during the filtering phase and during the selecting phase :
kubectl get services --all-namespaces -o json | jq -r '
.items[] | select( .metadata.name
| contains("my-srch-string")) |
{ name: .metadata.name, ns: .metadata.namespace
, nodePort: .spec.ports[].nodePort
, port: .spec.ports[].port}
'

failed to extract data from json with jq command

I've this json.
I want to extract test fields which their values equal to true.
I tried with jq and got that error, pls any fix ?
$- jq '.[].name | select(.[].test == "true")' ddd
jq: error (at ddd:12): Cannot iterate over string ("AA")
[
{
"name": "AA",
"program_url": "https://www.google.com",
"test": false
},
{
"name": "BB",
"program_url": "https://yahoo.com",
"test": true
}
]
Are you looking for this? It iterates over the array .[], selects those item objects whose .test field evaluates to true (implicit), and traverses further down to the .name field. Using the --raw-output (or -r) option renders the output raw text (instead of JSON string in this case).
jq -r '.[] | select(.test).name' ddd
BB
Demo

List key values of JSON file using jq

I have JSON file like the below; I need to list only x or y values only using jq:
{
"x":[
"a",
"b",
"c"
],
"y":[
"d",
"e"
]
}
I need to get only x values like
a
b
c
How can I do that?
Easy:
cat input.json | jq '.x[]'
.x: get value of x property
[]: access array elements
If you want it as a valid JSON array, remove the [] part: .x. --raw-output/-r outputs top-level strings without quotation marks, e.g.:
$ jq '.x' < input.json
[
"a",
"b",
"c"
]
$ jq '.x[]' < input.json
"a"
"b"
"c"
$ jq -r '.x[]' < input.json
a
b
c
Try it online

jq: How can a nested object be sliced to include the parent-key hierarchy?

Using Bash and jq, if I have a Bash variable filter F of the form .<key1>.<key2>...<keyN> and I want to slice a Bash variable JSON object O so that the result is just that slice of the object including all keys in F, how can this be done with jq?
For example, suppose:
O='
{
"a":
{
"b":
{
"c": { "p":1 },
"x": 1
},
"x": 2
},
"x": 3
}'
Then, doing:
F='.a.b.c'; jq -r "$F" <<<"$O"
results in:
{
"p": 1
}
But, I want the slice to include parent key hierarchy.
Inelegant Solution
I have come up with a solution, but it involves 2 calls to jq:
F='.a.b.c'; S="$(jq -r "$F" <<<"$O"); jq --null-input -r "$F |= $S"
that results in:
{
"a": {
"b": {
"c": {
"p": 1
}
}
}
}
The solution must work for any valid O and F Bash variable where O stores a JSON object and F is a simple filter of key names only as described above. For example:
F='.a.b'; S="$(jq -r "$F" <<<"$O")"; jq --null-input -r "$F |= $S"
results in:
{
"a": {
"b": {
"c": {
"p": 1
},
"x": 1
}
}
}
Can slicing an object with a key-hierarchy filter be done more simply in jq?
Provided $F is a valid jq path expression (i.e., so that jq -n "$F" works):
jq "$F as \$v | null | $F |= \$v" <<< "$O"
(I included the |= from your solution to show the similarity, but here you could drop the |.)

How to extract all (also nested) key names with jq

How can I extract all key names, even in nested objects with jq?
For example, I have json:
{
"a": 1,
"b": {
"c": 2
}
}
and I want to get list:
a, b, b.c
I know that for top level keys I can get this, with:
. | to_entries[] | .key, but what about keys in nested objects?
Short jq solution:
jq -r '[paths | join(".")]' jsonfile
The output:
[
"a",
"b",
"b.c"
]
paths function outputs the paths to all the elements in its input
join(".") - to concatenate keys within hierarchical paths
Given input foo.json
{"a":1,"b":[{"c":2}]}
jq '[
paths |
map(select(type!="number")) |
select(length > 0) |
join(".")
] | unique' foo.json
outputs
[
"a",
"b",
"b.c"
]