I have 2 report files like the following
report1.json
{
"examples": [
{
"description": "desc 1",
"full_description": "full_description 1",
"status": "status 1",
"file_path": "file_path 1",
"run_time": 0.01
}
]
}
and report2.json
{
"examples": [
{
"description": "desc 2",
"full_description": "full_description 2",
"status": "status 2",
"file_path": "file_path 2",
"run_time": 0.02
}
]
}
I want to combine it using jq command with hope the end result is as follows
{
"examples": [
{
"description": "desc 1",
"full_description": "full_description 1",
"status": "status 1",
"file_path": "file_path 1",
"run_time": 0.01
},
{
"description": "desc 2",
"full_description": "full_description 2",
"status": "status 2",
"file_path": "file_path 2",
"run_time": 0.02
}
]
}
i have tried using this script jq -s '.[0] * .[1]' report1.json report2.json but it doesn't work, is there any solution to be able to combine according to my expected result using jq command ?
Try this:
jq -s ' [ (.[0] | keys[]) as $k | reduce .[] as $item (null; .[$k] += $item[$k]) ] | add' report1.json report2.json
Take the first input (automatically in context), and operarte on all subsequent objects using inputs (without the -n option). Then, simply add up all items you care about:
jq '.examples += [inputs.examples[]]' report*.json
{
"examples": [
{
"description": "desc 1",
"full_description": "full_description 1",
"status": "status 1",
"file_path": "file_path 1",
"run_time": 0.01
},
{
"description": "desc 2",
"full_description": "full_description 2",
"status": "status 2",
"file_path": "file_path 2",
"run_time": 0.02
}
]
}
Demo
If the point of the question is that you don't know the name of the top-level key, then perhaps the following is close to what you want:
jq -n '
[inputs | to_entries] | add | {(first.key): (map(.value) | add) }
' report{1,2}.json
Here's a very simple and straightforward solution using slurp (reads whole file into memory):
jq -s '{examples: map(.examples[])}' report1.json report2.json
Related
First off thanks to everyone who takes time to answer questions for us who are learning or struggling. I have this code that works as I need, I had help from knittl earlier.
jq -r '["Username", "Full name", "Superuser", "Active"],
> (.User[]
> | select(.is_superuser)
> | [ .username, .full_name, .is_superuser, .is_active ])
> | #csv' lbc.noprod1.xxx.json > lbc.noprod1.xxx_Superuser.csv
I have tried to adjust it so that I can use the same concept but to get other information and have this
jq -r '["Interface Name", "Vlan ID", "IP address", "Subnet Mask"],
(.ServiceEngine[].data_vnics[].vlan_interfaces[]
| [ .if_name, .vlan_id])
(.ServiceEngine[].data_vnics[].vlan_interfaces[].vnic_networks[].ip[].ip_addr[]
| [.addr])
(.ServiceEngine[].data_vnics[].vlan_interfaces[].vnic_networks[].ip[]
| [.mask])
| #csv' 20221004_lbc.prod1.xxx.json > 20221004_lbc.prod1.xxx_VNIC.csv
I receive the error below
jq: error: syntax error, unexpected '(', expecting $end (Unix shell quoting issues?) at , line 4:
(.ServiceEngine[].data_vnics[].vlan_interfaces[].vnic_networks[].ip[].ip_addr[]
jq: 1 compile error
If it helps this is an extract from the JSON with fields that aren't relevant removed but all formatting kept
"ServiceEngine": [
{
"data_vnics": [
{
"vlan_interfaces": [
{
"if_name": "bond1.109",
"vlan_id": 109,
"vnic_networks": [
{
"ctlr_alloc": false,
"ip": {
"ip_addr": {
"addr": "123.123.123.123",
"type": "V4"
},
"mask": 24
},
"mode": "STATIC"
}
],
"vrf_ref": "/api/vrfcontext/?tenant=admin&name=branch-pci-client-vlan109&cloud=Default-Cloud"
},
{
"dhcp_enabled": true,
"enabled": true,
"if_name": "bond1.1622",
"ip6_autocfg_enabled": true,
"is_mgmt": false,
"vlan_id": 1622,
"vnic_networks": [
{
"ctlr_alloc": false,
"ip": {
"ip_addr": {
"addr": "456.456.456.456",
"type": "V4"
},
"mask": 22
},
"mode": "STATIC"
}
],
"vrf_ref": "/api/vrfcontext/?tenant=admin&name=onprem-pci-prod-vlan1622&cloud=Default-Cloud"
},
As always if you have any tips and suggestions I would be greatful.
Kind regards
I think you are looking for this:
["Interface Name", "Vlan ID", "IP address", "Subnet Mask"],
(
.ServiceEngine[].data_vnics[].vlan_interfaces[]
| . as { $if_name, $vlan_id }
| .vnic_networks[].ip
| [ $if_name, $vlan_id, .ip_addr.addr, .mask]
)
| #csv
or
["Interface Name", "Vlan ID", "IP address", "Subnet Mask"],
(
.ServiceEngine[].data_vnics[].vlan_interfaces[]
| [ .if_name, .vlan_id ] + (.vnic_networks[].ip | [.ip_addr.addr, .mask])
)
| #csv
or
["Interface Name", "Vlan ID", "IP address", "Subnet Mask"],
(
.ServiceEngine[].data_vnics[].vlan_interfaces[]
| { if_name, vlan_id, ips: .vnic_networks[].ip }
| [ .if_name, .vlan_id, (.ips|.ip_addr.addr, .mask) ]
)
| #csv
All three generate the same CSV with one line per IP. Interface name and VLAN id will be printed multiple times if they contain more than one IP.
I have an array of array as following
[
{
"devices": [
{
"files": [
{
"id": "2",
"type": "file"
}
],
"path": "/tmp/file1"
},
{
"files": [
{
"id": "3",
"type": "file"
}
],
"path": "/tmp/file2"
}
],
"name": "a"
},
{
"devices": [
{
"files": [
{
"id": "4",
"type": "file"
}
],
"path": "/tmp/tfile"
},
{
"files": [
{
"id": "5",
"type": "file"
}
],
"path": "/var/mfile"
}
],
"name": "b"
}
]
I'm looking for output like this
a /tmp/file1 2
a /tmp/file2 3
b /tmp/tfile 4
b /var/mfile 5
What I have tried
cat myfile.json | jq '.[] | "\(.name), \(.devices[].path) \(.devices[].files[].id)"'
and result is
"a, /tmp/file1 2"
"a, /tmp/file2 2"
"a, /tmp/file1 3"
"a, /tmp/file2 3"
"b, /tmp/tfile 4"
"b, /var/mfile 4"
"b, /tmp/tfile 5"
"b, /var/mfile 5"
but I'm unable to select a key for the value is in parent map.
I want to for each of the elements matching name == a, for each of a[path], get a[path][id].
Using .devices[] twice will iterate over the same .devices twice, giving you the cartesian product. Extract from within one iteration.
You can nest string iterpolation; otherwise collect into an array (here you'd need , as separator) and use join(" ") to concatenate
Use the -r (or --raw-output) flag to output raw text
jq -r '.[] | "\(.name) \(.devices[] | "\(.path) \(.files[].id)")"'
a /tmp/file1 2
a /tmp/file2 3
b /tmp/tfile 4
b /var/mfile 5
Demo
I have a json as below. I want to select list reference of item which has method is "method A". But I cannot query with operator == (with Jayway JSONPath evaluation)
$.items[*].[?(#.methods[*].name == 'method A')].reference
But when I replace operator as contains, the jsonpath works.
$.items[*].[?(#.methods[*].name contains 'method A')].reference
I don't know why operator == does not work. Could anyone help me explain the reason?
JSON:
{
"name": "List codes",
"items": [
{
"name": "Cash",
"reference": "CA",
"methods": [
{
"name": "method A",
"id": "3543"
},
{
"name": "method B",
"id": "3544"
}
]
},
{
"name": "Debt",
"reference": "DE",
"methods": [
{
"name": "method C",
"id": "3545"
},
{
"name": "method B",
"id": "3544"
}
]
},
{
"name": "Property",
"reference": "PR",
"methods": [
{
"name": "method C",
"id": "3545"
},
{
"name": "method A",
"id": "3543"
}
]
}
]
}
#.methods[*].name will yield multiple results resulting into an array. You cannot use == to compare list of values with a string.
if you need to use == operator then you have to use the index along with ||
$.items[?(#.methods[0].name == 'method A' || #.methods[1].name == 'method A')].reference
What I need is simply to extract id, sales from sorted_employees AND full name for that employee from employees.. like this:
{ "Full name": "John Doe", "ID": "employee1", "Sales": "26" }
{ "Full name": "Sam Jones", "ID": "employee2", "Sales": "119" }
What would be the easiest way to combine these 2 arrays ( employees & sorted_employees ) ? I have problems merging the result, I have tried to cast results into an array and I tried purely with jq filters.. but it doesn't want to give me what I need..
employees_id=$( echo "${json_data}" | jq -r '.employees[] | .id' )
sorted_employees_id=$( echo "${json_data}" | jq -r '.sorted_employees[] | .id' )
sorted_employees_sales=$( echo "${json_data}" | jq '.sorted_employees[] | .sales' )
{
"employees": [ {
"started_at": "2018-05-01 12.00",
"id": "employee1",
"facebook": "https://fb/john_doe",
"full name": "John Doe"
}, {
"started_at": "2017-05-01 12.00",
"id": "employee2",
"facebook": "https://fb/sam_jones",
"full name": "Sam Jones"
}, {
"started_at": "2016-05-01 12.00",
"id": "employee3",
"facebook": "https://fb/jane_roe",
"full name": "Jane Roe"
}],
"sorted_employees": [{
"id": "employee1",
"sales": 26
}, {
"id": "employee2",
"sales": 119
}, {
"id": "employee3",
"sales": 84
}]
}
You could combine the two arrays and just group by the common ID field and form the desired output object
jq '.employees + .sorted_employees | group_by(.id) |
map({"Full name": .[0]."full name", ID: .[0].id, "Sales": .[1].sales})'
I'd like
"1": {
"id": "1",
"type": "select",
"label": "country :",
"choices": {
"1": {
"label": "Canada CAN",
"value": "",
},
"2": {
"label": "United States USA",
"value": ""
}
}
}
to produce
"1": {
"id": "1",
"type": "select",
"label": "country :",
"choices": {
"1": {
"label": "Canada",
"value": "CAN",
},
"2": {
"label": "United States",
"value": "USA"
}
}
}
By now I have a two-step solution consisting of a sed-like function
def do_extract:
if .value | test("^$") then
(.value = (.label | capture(".* (?<code>...)")).code) | .label = (.label | capture("(?<name>.*) ...$").name)
else
.
end;
and a direct access to the sub-tree []."1"."choices"|keys_unsorted as $key|map_values(do_extract) but I have to manually copy-paste the output in place of the original "choices" dict.
Is there a way to do the function but still print the surrounding datas ?
Thanks
Well to get your desired result, you could do this:
.[].choices[] |= (.label | capture("^(?<label>.*?) (?<value>[^ ]+)$"))
To do that within your function, I'd change it to this:
def do_extract:
if .value == "" then
(.label | capture("^(?<label>.*?) (?<value>[^ ]+)$"))
else
.
end;
Then use it:
.[].choices[] |= do_extract