Recurse for object if exists in JQ - json

I have the following structure:
{
"hits":
[
{
"_index": "main"
},
{
"_index": "main",
"accordions": [
{
"id": "1",
"accordionBody": "body1",
"accordionInnerButtonTexts": [
"button11",
"button12"
]
},
{
"id": "2",
"accordionBody": "body2",
"accordionInnerButtonTexts": [
"button21",
"button22"
]
}
]
}
]
}
I want to get to this structure:
{
"index": "main"
}
{
"index": "main",
"accordions":
[
{
"id": "1",
"accordionBody": "body1",
"accordionInnerButtonTexts": [
"button11",
"button12"
]
},
{
"id": "2",
"accordionBody": "body2",
"accordionInnerButtonTexts": [
"button21",
"button22"
]
}
]
}
Which means that I always want to include the _index-field as index, and I want to include the whole accordions-list IF IT EXISTS in the object. Here is my attempt:
.hits[] | {index: ._index, accordions: recurse(.accordions[]?)}
It does not produce what I want:
{
"index": "main",
"accordions": {
"_index": "main"
}
}
{
"index": "main",
"accordions": {
"_index": "main",
"accordions": [
{
"id": "1",
"accordionBody": "body1",
"accordionInnerButtonTexts": [
"button11",
"button12"
]
},
{
"id": "2",
"accordionBody": "body2",
"accordionInnerButtonTexts": [
"button21",
"button22"
]
}
]
}
}
{
"index": "main",
"accordions": {
"id": "1",
"accordionBody": "body1",
"accordionInnerButtonTexts": [
"button11",
"button12"
]
}
}
{
"index": "main",
"accordions": {
"id": "2",
"accordionBody": "body2",
"accordionInnerButtonTexts": [
"button21",
"button22"
]
}
}
It seems to create a list of all different permutations given by mixing the objects. This is not what I want. What is the correct jq command, and what is my mistake?

The problem as stated does not require any recursion. Using your attempt as a model, one could in fact simply write:
.hits[]
| {index: ._index}
+ (if has("accordions") then {accordions} else {} end)
Or, with quite different semantics:
.hits[] | {index: ._index} + . | del(._index)

Related

JQ: group by into single object with groups as keys

I have the following data:
[
{
"company.u_ats_region": "Region1",
"hostname": "host1",
"install_status": "1",
"os": "Windows",
"os_domain": "test.com"
},
{
"company.u_ats_region": "Region2",
"hostname": "host2",
"install_status": "1",
"os": "Windows",
"os_domain": "test.com"
},
{
"company.u_ats_region": "Region3",
"hostname": "host3",
"install_status": "7",
"os": "Windows",
"os_domain": "test.com"
}
]
And I've been using this query
{count: length,
regions: [group_by(."company.u_ats_region")[] |
{( [0]."company.u_ats_region"): [.[] |
{name: (.hostname+"."+.os_domain),
os: .os}]}]}
to convert the data into the following:
{
"count": 3,
"regions": [
{
"Region1": [
{
"name": "host1.test.com",
"os": "Windows"
}
]
},
{
"Region2": [
{
"name": "host2.test.com",
"os": "Windows"
}
]
},
{
"Region3": [
{
"name": "host3.test.com",
"os": "Windows"
}
]
}
]
}
This is close to what I'm trying to achieve but I would like 'regions' to be a single object with each region being a key within that object like this:
{
"count": 3,
"regions": {
"Region1": [
{
"name": "host1.test.com",
"os": "Windows"
}
],
"Region2": [
{
"name": "host2.test.com",
"os": "Windows"
}
],
"Region3": [
{
"name": "host3.test.com",
"os": "Windows"
}
]
}
}
I have tried playing around with 'add' but that still didn't bring me any closer to the result I'm trying to achieve. Any help is appreciated!
Creating an object with key and value fields, then using from_entries would be one way:
{
count: length,
regions: group_by(."company.u_ats_region")
| map({
key: .[0]."company.u_ats_region",
value: map({name: "\(.hostname).\(.os_domain)", os})
})
| from_entries
}
{
"count": 3,
"regions": {
"Region1": [
{
"name": "host1.test.com",
"os": "Windows"
}
],
"Region2": [
{
"name": "host2.test.com",
"os": "Windows"
}
],
"Region3": [
{
"name": "host3.test.com",
"os": "Windows"
}
]
}
}
Demo
You can define a custom function which performs the grouping and then tranfsorm the result. Using a function avoids having to repeat the selector:
def group_to_obj(f):
group_by(f) | map({key:first|f, value:.}) | from_entries;
{
count: length,
regions: group_to_obj(."company.u_ats_region")
| map_values(map({name: "\(.hostname).\(.os_domain)", os}))
}
Output:
{
"count": 3,
"regions": {
"Region1": [
{
"name": "host1.test.com",
"os": "Windows"
}
],
"Region2": [
{
"name": "host2.test.com",
"os": "Windows"
}
],
"Region3": [
{
"name": "host3.test.com",
"os": "Windows"
}
]
}
}
Using reduce to iteratively build up the arrays would be another way:
{
count: length,
regions: (
reduce .[] as $i ({};
.[$i."company.u_ats_region"] += [$i | {name: "\(.hostname).\(.os_domain)", os}]
)
)
}
{
"count": 3,
"regions": {
"Region1": [
{
"name": "host1.test.com",
"os": "Windows"
}
],
"Region2": [
{
"name": "host2.test.com",
"os": "Windows"
}
],
"Region3": [
{
"name": "host3.test.com",
"os": "Windows"
}
]
}
}
Demo

Sort complex JSON object by specific property

How can I sort the given JSON object with property count. I want to sort the entire sub-object. The higher the count value should come on the top an so on.
{
"Resource": [
{
"details": [
{
"value": "3.70"
},
{
"value": "3.09"
}
],
"work": {
"count": 1
}
},
{
"details": [
{
"value": "4"
},
{
"value": "5"
}
],
"work": {
"count": 2
},
{
"details": [
{
"value": "5"
},
{
"value": "5"
}
],
"work": "null"
}
]
}
You can try this example to sort your data:
data = {
"data": {
"Resource": [
{
"details": [{"value": "3.70"}, {"value": "3.09"}],
"work": {"count": 1},
},
{"details": [{"value": "4"}, {"value": "5"}], "work": {"count": 2}},
]
}
}
# sort by 'work'/'count'
data["data"]["Resource"] = sorted(
data["data"]["Resource"], key=lambda r: r["work"]["count"]
)
# sort by 'details'/'value'
for r in data["data"]["Resource"]:
r["details"] = sorted(r["details"], key=lambda k: float(k["value"]))
# pretty print:
import json
print(json.dumps(data, indent=4))
Prints:
{
"data": {
"Resource": [
{
"details": [
{
"value": "3.09"
},
{
"value": "3.70"
}
],
"work": {
"count": 1
}
},
{
"details": [
{
"value": "4"
},
{
"value": "5"
}
],
"work": {
"count": 2
}
}
]
}
}

How can I create a hierarchical json response in FLASK

I have a single table in database like database table. I want to search a child from database and return a hierarchical JSON to a front end in order to create a tree. How can I do that in FLASK.
My expected JSON for mat should be like expected JSON
Since you have tagged your question with flask, this post assumes you are using Python as well. To format your database values in JSON string, you can query the db and then use recursion:
import sqlite3, collections
d = list(sqlite3.connect('file.db').cursor().execute("select * from values"))
def get_tree(vals):
_d = collections.defaultdict(list)
for a, *b in vals:
_d[a].append(b)
return [{'name':a, **({} if not (c:=list(filter(None, b))) else {'children':get_tree(b)})} for a, b in _d.items()]
import json
print(json.dumps(get_tree(d), indent=4))
Output:
[
{
"name": "AA",
"children": [
{
"name": "BB",
"children": [
{
"name": "EE",
"children": [
{
"name": "JJ",
"children": [
{
"name": "EEV"
},
{
"name": "FFW"
}
]
},
{
"name": "KK",
"children": [
{
"name": "HHX"
}
]
}
]
}
]
},
{
"name": "CC",
"children": [
{
"name": "FF",
"children": [
{
"name": "LL",
"children": [
{
"name": "QQY"
}
]
},
{
"name": "MM",
"children": [
{
"name": "RRV"
}
]
}
]
},
{
"name": "GG",
"children": [
{
"name": "NN",
"children": [
{
"name": "SSW"
}
]
}
]
}
]
},
{
"name": "DD",
"children": [
{
"name": "HH",
"children": [
{
"name": "OO",
"children": [
{
"name": "TTZ"
}
]
}
]
},
{
"name": "II",
"children": [
{
"name": "PP",
"children": [
{
"name": "UUW"
}
]
}
]
}
]
}
]
}
]

read hyperopt parameters from json

I want to read hyperopt parameters from a JSON file.
My JSON file would be like:
[
{
"id": "121",
"model": [
{
"model_name": "power",
"estimator_type": [
{
"type": "Polynomial",
"degree": [2, 3, 4]
},
{
"type": "svm",
"C": [0, 1],
"kernel": [
{
"ktype": "linear"
},
{
"ktype": "RBF",
"width": [0, 1]
}
]
}
],
"cut_values": {
"qids": ["1234"]
}
},
{
"model_name": "speed",
"estimator_type": [
{
"type": "Polynomial",
"degree": ["quniform", 2, 3]
}
],
"cut_values": null
}
]
},
{
"id": "123",
"model": [
{
"model_name": "power",
"estimator_type": [
{
"type": "LinearRegression"
}
],
"cut_values": null
}
]
}
]
I have checked this post but with no success for more complex JSON like the one above.
I want to be able to create a space like 2.2 A Search Space Example: scikit-learn.

Aggregate and sum json data in python

I am new to python, using python3. I have json data like:
{
"message": {
"count": 46,
"limit": 1000,
"schools": [
{
"class": "1",
"class_id": "1c8***",
"charges": [
{
"cost": 10,
"breakdown": [
{
"books": "1",
"unitQuantity": "10"
}
]
}
],
"area": "maccau"
},
{
"class": "2",
"class_id": "1c3***",
"charges": [
{
"cost": 100,
"breakdown": [
{
"books": "1",
"unitQuantity": "100"
}
]
}
],
"area": "maccau"
},
{
"class": "1",
"class_id": "1c3***",
"charges": [
{
"cost": 10,
"breakdown": [
{
"books": "1",
"unitQuantity": "10"
}
]
}
],
"area": "maccau"
},
{
"class": "2",
"class_id": "1c8***",
"charges": [
{
"cost": 50,
"breakdown": [
{
"books": "1",
"unitQuantity": "50"
}
]
}
],
"area": "maccau"
}
],
"url": {
"link": "/"
}
}
}
I was able to use json.loads to load data and I am trying to get results like:
class Cost
1 20
2 150
I tried converting json to a dictionary:
item_dict = json.load(json_data)
Tried to get data out using for loop and checking if class = 1 and then summing up the cost. But I feel like that is not the best approach. Can someone please tell me what would be the best way of doing this?