jq: selecting subset of keys from nested object - json

Input:
{"success": true, "results": {"a": …, "b": …, "c": …}}
Desired output, given I want to keep b:
{"success": true, "results": {"b": …}}
Things I tried:
$ jq 'del(select(.results.b | not))'
{"success": true, "results": {"a": …, "b": …, "c": …}}
# removes nothing from "results"
$ jq 'with_entries(select(.key == "success" or .key == "results.b"))'
{"success": true}
# nested comparison not understood; returns only "success"
Thanks!

Here is one solution:
.results |= {b}
Sample Run
$ jq -M '.results |= {b}' <<< '{"success":true, "results":{"a": "…", "b": "…", "c": "…"}}'
{
"success": true,
"results": {
"b": "…"
}
}
Try it online at jqplay.org

Another way using nodejs and shell :
Code :
$ node<<EOF
var obj = $(</tmp/file.json);
delete obj.results.a;
delete obj.results.c;
console.log(JSON.stringify(obj));
EOF
OUTPUT :
{"success":true,"results":{"b":"bbb"}}

Related

Linux command to print all jsons of same key

I have json as a string "Str"
"{
"A": {
"id": 4
},
"B": {//Something},
"C": {
"A": {
"id": 2
}
},
"E": {
"A": null
},
"F": {//Something}
}"
I wanted all non null values of "A" which can be repeated anywhere in json. I wanted output like all contents of "A"
{"id": 4}
{"id": 2}
Can you please help me with Linux command to get this ?
Instead of line oriented ones use a tool which is capable of parsing JSON values syntax wise. An example using jq:
$ json_value='{"A":{"id":4},"B":{"foo":0},"C":{"A":{"id":2}},"E":{"A":null},"F":{"foo":0}}'
$
$ jq -c '..|objects|.A//empty' <<< "$json_value"
{"id":4}
{"id":2}
.. # list nodes recursively
| objects # select objects
| .A // empty # print A's value if present.

jq select subset of nested keys

I'm trying to build a SQL layer on top of jq for json files and I would like to implement the select. So far I got that:
function join() {
# If no arguments, do nothing.
# This avoids confusing errors in some shells.
if [ $# -eq 0 ]; then
return
fi
local joiner="$1"
shift
while [ $# -gt 1 ]; do
printf "%s%s" "$1" "$joiner"
shift
done
printf '%s\n' "$1"
}
function jselect {
keys=`join "\":1, \"" $#`
jq "with_entries(select(.key | in({\"$keys\":1})))"
}
allows me to do
$ echo '{"success":true, "failure":false, "results":{"a": "...", "b": "...", "c": "..."}}' | jselect success results
>>> {
"success": true,
"results": {
"a": "...",
"b": "...",
"c": "..."
}
}
but I would like to be able to index nested properties as well something like:
$ echo '{"success":true, "failure":false, "results":{"a": "...", "b": "...", "c": "..."}}' | jselect success results
>>> {
"success": true,
"results": {
"b": "..."
}
}
or
>>> {
"success": true,
"results.b": "..."
}
Any idea?
Unless I didn't understand what you're asking, I think there is no need for extra shell script, you can use plain jq script:
echo '{"success":true, "failure":false, "results":{"a": "...", "b": "...", "c": "..."}}' | jq '{ success, results }'
The jq script only selects the 2 objects you want. Note the shorter form that uses 1 keyword per object (instead of "success":.success).
echo '{"success":true, "failure":false, "results":{"a": "...", "b": "...", "c": "..."}}' | jq '{ success, "results.b":.results.b }'
This script is almost the same except that the object name is explicit.

Concat 2 arrays inside object based on object key/value

I have multiple json objects which could be less when i merge the arrays if a object key matches the same value as the next json object. I'm trying to accomplish this with jq.
I think i have to use group_by(.name) first to group matching keys. I'm also using slurp to first wrap all objects into one big array.
I don't have anything working for now.
given:
{
"name": "a",
"list": [ "a1", "a2" ]
}
{
"name": "a",
"list": [ "a3", "a4" ]
}
{
"name": "b",
"list": [ "b1", "b2" ]
}
should result in:
{
"name": "a",
"list": [ "a1", "a2", "a3", "a4" ]
}
{
"name": "b",
"list": [ "b1", "b2" ]
}
You can use reduce like this:
$ jq -c -n 'reduce inputs as $p ({}; .[$p.name] |= { name : $p.name, list : (.list + $p.list) }) | .[]' file
{"name":"a","list":["a1","a2","a3","a4"]}
{"name":"b","list":["b1","b2"]}
Here's a simple and efficient solution that uses a common "aggregate by" technique:
reduce inputs as $kv ({}; .[$kv.name] += $kv.list)
| keys_unsorted[] as $k
| {name: $k, list: .[$k]}
Since inputs has been used here, the -n command-line option of jq should be specified.

Extracting element from array in JSON with jq returns "Cannot index array with string"

I have a JSON file:
$ cat ~/tmp/example1.json
[
{
"keyProp": 11111111111111,
"values": [
"VALUE1"
]
},
{
"keyProp": 2222,
"values": [
"VALUE2"
]
}
]
I want to use jq to select values where keyProp==11111111111111. Expected output is 'VALUE2'
I have tried but without result:
cat ~/tmp/example1.json | jq 'select(.keyProp==11111111111111)'
jq: error (at <stdin>:14): Cannot index array with string "keyProp"
To select a block you need to use the expression described in the docs:
select(boolean_expression)
The function select(foo) produces its input unchanged if foo returns
true for that input, and produces no output otherwise.
It’s useful for filtering lists: [1,2,3] | map(select(. >= 2)) will
give you [2,3].
jq '.[] | select(.id == "second")'
Input [{"id": "first", "val": 1}, {"id": "second", "val": 2}]
Output {"id": "second", "val": 2}
So in this case you need to say:
$ jq '.[] | select(.keyProp==11111111111111)' file
{
"values": [
"VALUE1"
],
"keyProp": 11111111111111
}
To extract the list in value, just say so:
$ jq '.[] | select(.keyProp==11111111111111).values' file
[
"VALUE1"
]
You can even extract the first value by using indexes:
$ jq '.[] | select(.keyProp==11111111111111).values[0]' file
"VALUE1"

Parse JSON data into a variable assignment format

I am trying to parse JSON data into variable format
[
{
"Name" : "a",
"Value" : "1"
},
{
"Name" : "b",
"Value" : "2"
},
{
"Name" : "c",
"Value" : "3"
}
]
output should be like
a=1
b=2
c=3
This is what I tried, but it is not giving the expected result:
jq '.[].Value' file.txt
Since you're only printing out two values, it might just be easier to print out the strings directly.
$ jq -r '.[] | "\(.Name)=\(.Value)"' file.txt
You can use the following jq command:
jq -r '.[]|[.Name,.Value]|join("=")' file.json
Output:
a=1
b=2
c=3
Using jq:
jq 'map({(.Name):.Value})|add|.//={}' < data.json
Produces:
{
"a": "1",
"b": "2",
"c": "3"
}
If you have jq version 1.5+, you can use from_entries instead.
This does it
python3 -c 'import json; print("\n".join(["{}={}".format(x["Value"], x["Name"]) for x in json.load(open("file.json"))]))'
result
a=1
b=2
c=3