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
Related
I am trying to update a json file using jq. My json file looks like
{
"A": "123",
"B": "456",
"C": "789",
"D": []
}
Here the value for key D is empty so I am adding some values to it. And this is working
Now, if for some reason the key doesn't exist then I need to first create the key D. And I am not able to achieve this
{
"A": "123",
"B": "456",
"C": "789",
}
cat test.json | jq 'has("D")' = false && cat test.json jq --argjson addobj '{"D": "[]"}'
I am getting the error
jq: error: Could not open file =: No such file or directory
jq: error: Could not open file false: No such file or directory
expected output
{
"A": "123",
"B": "456",
"C": "789",
"D": []
}
Can anyone please let me know what is the issue here and how to resolve it?
Thanks in advance.
P.S: Please let me know if any info is missing here
Your problem is not (only) with jq, but with shell syntax.
But if all you are trying to do is to update the value of key D whether it exists or not, then you don't need any checks and can simply assign the new value:
$ jq '.D = ["new value"]' test.json
{
"A": "123",
"B": "456",
"C": "789",
"D": [
"new value"
]
}
If you want to modify the current value, the operator |= might be helpful.
An alternative, equivalent program would be '. + { D: ["new value"] }'
If you really want to fix your script, here's a working version of it:
if jq -e 'has("D")' test.json >/dev/null; then
# key exists
jq --argjson addobj '{"D": "[]"}' 'your program here' test.json
else
# key doesn't exist
jq 'your other program here'
fi
But this is arguably easier in jq directly:
jq --argjson addobj '{"D": "[]"}' '
if has("D") then
# D exists
. # <- your jq program
else
# D doesn't exist
. # <- your other jq program
end
' test.json
If your goal is to simply insert the key with a default value if it doesn't exist, but keep any existing value, the following simple jq program (and nothing else) should take care of that:
jq '{D: []} + .' test.json
(keys in the RHS overwrite keys from the LHS – {a:1}+{a:2} becomes {a:2})
Objects in JavaScript (and by extension JSON), are a bag of unordered key-value pairs and {a:1,b:2} is the same object as {b:2,a:1}.
However, jq mostly keeps order of keys (although I don't think this is specified/guaranteed). So, a slightly more complicated version which puts D at the end of the object, but keeps existing values would be:
jq '.D |= (. // [])' test.json
How to get the unique keys from attributes key with JQ
{"id":1, "attributes":{"a": 1, "b": 2, "c": 3}}
{"id":2, "attributes":{"a": 4, "b": 5, "d": 6}}
{"id":3, "name":"ABC"}
Result like this
[
"a",
"b",
"c",
"d"
]
I'm try like this
jq '.attributes' test.json | jq -r '[inputs | keys[]] | unique | sort'
or
jq -r '[inputs.attributes | keys[]] | unique | sort' test.json
but getting error
jq: error (at :11): null (null) has no keys
One way could be using reduce on subsequent inputs:
jq 'reduce inputs.attributes as $a (.attributes; . + $a) | keys'
[
"a",
"b",
"c",
"d"
]
Demo
Along the lines of your second attempt:
jq -n '[inputs.attributes // empty | keys_unsorted[]] | unique'
The important point is that we have to take care of the case where there is no "attributes" key.
Note also that unique sorts, so (unless you're using gojq) we can use keys_unsorted to avoid redundant sorting.
With slurp:
jq -s 'map(.attributes|keys?)|add|unique' test.json
-s loads the input file as array
map(.attributes|keys?) extracts only the keys (ignoring errors, such as trying to get keys of null)
add merges all nested arrays into a single array ([[1,2],[2,3]] becomes [1,2,2,3])
unique sorts and removes duplicates
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
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 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"
]