How do I collect values by keys from different levels in JQ? - json

Let's suppose I have a JSON like this:
[
{
"a": 1,
"l": [
{"b": "z"},
{"b": "x"}
]
},
{
"a": 2,
"l": [
{"b": "c"}
]
}
]
I want to collect the data from all embedded arrays and to get an array of all objects with "a" and "b" values. For the JSON above the result should be:
[
{"a": 1, "b": "z"},
{"a": 1, "b": "x"},
{"a": 2, "b": "c"}
]
What JQ expression do I need to try to solve the issue?

You can use .l[] within the expression in order to return each element of the array returned in the response. So, use this one below
map({a} + .l[])
Demo

Related

How to update the value of the item in an array if it exists in json using jq?

I have a Json file which I want to update using jq. I am working on Ubuntu with jq-1.6
test_data.json
{
"A": "12",
"B": "34",
"C": [
["X", "test1"],
["Y", "test2"],
["Z", "test3"]
]
}
Now I want to update array C with new key:value pair. But, if the any of the key already exists then it's value should be updated.
update='[
["Z", "test4"],
["D", "test5"],
["E", "test6"]
]'
In this case the item Z already exists in test_data.json but update has new value for the item.
Expected output:
{
"A": "12",
"B": "34",
"C": [
["X", "test1"],
["Y", "test2"],
["Z", "test4"],
["D", "test5"],
["E", "test6"]
]
}
So far, I could do
cat test_data.json | jq --argjson val "${update}" '.C += $val')
But this is not updating value for item Z, instead adding new entry.
Can anyone please let me know how to resolve this?
Thanks in advance.
The .C array and the $update array both have arrays as items. You need to consider their first item to be a unique key, so that clashes can lead to overwrites. One way could be turning them into an INDEX object first, then add up those, and retrieve their items back into an array:
jq --argjson val "$update" '.C |= [[., $val | INDEX(.[0])] | add[]]' test_data.json
{
"A": "12",
"B": "34",
"C": [
[
"X",
"test1"
],
[
"Y",
"test2"
],
[
"Z",
"test4"
],
[
"D",
"test5"
],
[
"E",
"test6"
]
]
}

Conditional deletion from array of field A with condition on field B

Let's say I have a json with an array inside. Say that the elements of this array are objects with keys A and B. I would like to remove the B objects on the elements where A objects meet a certain condition.
For example, I would like to remove the B objects where A is greater than 5, transforming
{
"title": "myTitle",
"myArray": [
{
"A": 1,
"B": "foo"
},
{
"A": 4,
"B": "bar"
},
{
"A": 7,
"B": "barfoo"
},
{
"A": 9,
"B": "foobar"
}
]
}
into
{
"title": "myTitle",
"myArray": [
{
"A": 1,
"B": "foo"
},
{
"A": 4,
"B": "bar"
},
{
"A": 7
},
{
"A": 9
}
]
}
The task seems easy enough and if I had't have to keep the A's it would be a simple del(select..) thing. There surely must be an elegant way to do this as well?
Thank you!
You can still use a del(select..) thing.
.myArray[] |= del(select(.A > 5) .B)
demo at jqplay.org

Reshape a jq array with summarized data

New to jq but I've managed to group a load of data which I would now like summarized in a different format. Original data after group by and mapping:
[
{
"Agents": "a",
"Count": 1
},
{
"Agents": "b",
"Count": 50
},
{
"Agents": "c",
"Count": 25
},
{
"Agents": "d",
"Count": 1
},
{
"Agents": "e",
"Count": 4
},
{
"Agents": "f",
"Count": 4
},
{
"Agents": "g",
"Count": 4
}
]
and I would like this output:
{
"Count": 7,
"Agents": {
"a": 1,
"b": 50,
"c": 25,
"d": 1,
"e": 4,
"f": 4,
"g": 4
}
}
How exactly might I do this in jq please because it requires mapping the values as field names?
Another variant using reduce would be to do. The reduce expression takes the array as input and puts the key as the Agents and the value as its corresponding Count value.
jq '{ Count: length, Agents: (reduce .[] as $d ({}; .[$d.Agents] = $d.Count)) }'
The Object Value Iterator .[] used to construct the JSON. For a given .["a"], it returns "a" which is how the keys are constructed in the final JSON.
Use map to create an input for from_entries:
map({key: .Agents, value: .Count}) | {Count: length, Agents: from_entries}
map produces a list of objects like [{"key": "a", "value": 1}, ...]. from_entries turns that into a single object {"a": 1, ...}. In the final object, both length and from_entries get the same array as input, and their outputs are used to create the final object with Count and Agents keys.

KarateException Missing Property in path - JSON

I was trying to match particular variable from response and tried as below. But im getting error saying KarateException Missing Property in path $['Odata']. My question is: how we can modify so that we won't get this error?
Feature:
And match response.#odata.context.a.b contains '<b>'
Examples:
|b|
|b1 |
|b2 |
Response is
{
"#odata.context": "$metadata#Accounts",
"a": [
{
"c": 145729,
"b": "b1",
"d": "ON",
},
{
"c": 145729,
"b": "b2",
"d": "ON",
}
]
}
I think you are confused with the structure of your JSON. Also note that when the JSON key has special characters, you need to change the way you use them in path expressions. You can try paste the below in a new Scenario and see it work:
* def response =
"""
{
"#odata.context": "$metadata#Accounts",
"a": [
{
"c": 145729,
"b": "b1",
"d": "ON",
},
{
"c": 145729,
"b": "b2",
"d": "ON",
}
]
}
"""
* match response['#odata.context'] == '$metadata#Accounts'
* match response.a[0].b == 'b1'
* match response.a[1].b == 'b2'

how to remove duplicates from a json defaultdict?

(Re-post with accurate data sample)
I have a json dictionary where each value in turn is a defaultdict as follows:
"Parent_Key_A": [{"a": 1.0, "b": 2.0}, {"a": 5.1, "c": 10}, {"b": 20.3, "a": 1.0}]
I am trying to remove both duplicate keys and values so that each element of the json has unique values. So for the above example, I am looking for output something like this:
"Parent_Key_A": {"a":[1.0,5.1], "b":[2.0,20.3], "c":[10]}
Then I need to write this output to a json file. I tried using set to handle duplicates but set is not json serializable.
Any suggestions on how to handle this?
The solution using itertools.chain() and itertools.groupby() functions:
import itertools, json
input_d = { "Parent_Key_A": [{"a": 1.0, "b": 2.0}, {"a": 5.1, "c": 10}, {"b": 20.3, "a": 1.0}] }
items = itertools.chain.from_iterable(list(d.items()) for d in input_d["Parent_Key_A"])
# dict comprehension (updated syntax here)
input_d["Parent_Key_A"] = { k:[i[1] for i in sorted(set(g))]
for k,g in itertools.groupby(sorted(items), key=lambda x: x[0]) }
print(input_d)
The output:
{'Parent_Key_A': {'a': [1.0, 5.1], 'b': [2.0, 20.3], 'c': [10]}}
Printing to json file:
json.dump(input_d, open('output.json', 'w+'), indent=4)
output.json contents:
{
"Parent_Key_A": {
"a": [
1.0,
5.1
],
"c": [
10
],
"b": [
2.0,
20.3
]
}
}