jq: exclude object with specified key - jq

Input:
{
"name":"JSON",
"good":true,
"target":"yes"
}
{
"name":"XML",
"good":false
}
I would like to exclude object WITHOUT key "target", as follow but NOT has:
jq -r ".| select(has(\"target\"))"
expected output:
{
"name":"XML",
"good":false
}
tried this:
jq -r " . | del(select(has(\"target\")))"
but there are two returned objects, one of them NULL
null
{
"good": false,
"name": "XML"
}

Select those who do not have target; that way, you do not use del:
jq -r 'select(has("target") | not)'

Related

jq: Use context object as key in query from root

I have a JSON object where the relevant parts are of the form
{
"_meta": {
"hostvars": {
"name_1": {
"ansible_host": "10.0.0.1"
},
"name_2": {
"ansible_host": "10.0.0.2"
},
"name_3": {
"ansible_host": "10.0.0.3"
}
}
},
...
"nodes": {
"hosts": [
"name_1",
"name_2"
]
}
}
(the output of ansible-inventory --list, for reference).
I would like to use jq to produce a list of IPs of the nodes hosts by looking up the names in ._meta.hostvars. In the example, the output should be:
10.0.0.1
10.0.0.2
Note that 10.0.0.3 should not be included because name_3 is not in the .nodes.hosts list. So just doing jq -r '._meta.hostvars[].ansible_host' doesn't work.
I've tried jq '.nodes.hosts[] | ._meta.hostvars[.].ansible_host' but that fails because ._meta doesn't scan from the root after the pipe.
You can store the root in a variable before changing the context:
jq -r '. as $root | .nodes.hosts[] | $root._meta.hostvars[.].ansible_host'
But a better solution is to just inline the "hosts" query:
jq -r '._meta.hostvars[.nodes.hosts[]].ansible_host'

Using jq to suffix a string to a field in an object not containing it

I have a json as follows:
{
"$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"batchPools": {
"value": [
{
"networkConfiguration": {
"subnetId": "/subscriptions/xxxx/resourceGroups/xxx/providers/Microsoft.Network/virtualNetworks/xxxxx/subnets/sample-name-batch",
"subnetAddressPrefix": ""
}
},
{
"networkConfiguration": {
"subnetId": "/subscriptions/xxxx/resourceGroups/xxx/providers/Microsoft.Network/virtualNetworks/xxxxx/subnets/sample-name",
"subnetAddressPrefix": ""
}
}
]
}
}
}
I need to check if any of the networkConfiguration.subnetID under the array value contains the string batch. If yes then nothing needs to be done. Else, append -batch to the existing value. In this case, only the second networkConfiguration.subnetID of the array should be updated.
I tried the following:
(.parameters.batchPools.value[] | select(.networkConfiguration.subnetId | contains("-batch") | not) | .networkConfiguration.subnetId) |= (.networkConfiguration.subnetId+"-batch")
I get the following error:
jq: error (at <stdin>:38): Cannot index string with string "networkConfiguration" exit status 5
I tried this:
(.parameters.batchPools.value[] | select(.networkConfiguration.subnetId | contains("batch") | not) | .networkConfiguration.subnetId) |= "someValue"
This worked fine and replaced the entire subnetId with someValue. I am not able to figure out why the previous command is not working out. Please help.
You don't need to use the whole path of subnetId again. You've already selected that node from the pipeline before. Just use the += append operator to suffix the required string
( .parameters.batchPools.value[] |
select(.networkConfiguration.subnetId | contains("batch") | not) |
.networkConfiguration.subnetId ) += "-batch"
jqplay - Online demo

jq syntax help for querying lists output

I need help in correcting jq test cases syntax. Following is output file & trying to test ID list with command below. Gives error index to string type.
[[ $(echo $output| jq -r '.output.value[] | select(.identity).id_list') == *"id2"* ]]
output = {
"resource_output": {
"value": {
"identity": [
{
"id_list": [
"/subscriptions/---/id1",
"/subscriptions/---/id2",
"/subscriptions/--/id3"
],
"principal_id": "",
"tenant_id": "",
"type": "managed"
}
]
}
}
Your query does not match the sample JSON, and you have not indicated what output you are expecting, but the following variation of your query illustrates how to use select and test with your data along the lines suggested by your attempt:
echo "$output" |
jq -r '.resource_output.identity[].id_list[] | select(test("id2"))'
Output:
/subscriptions/---/id2

jq: search by value from another array element

I have an array of objects of various types which reference one another with UUIDs (a terraform.tfstate file). I'd like to select one value from one such object based on the appearance of a different value in another object, where the two objects are related by one of those UUIDs.
By way of example, I can do this:
$ jq '.modules[].resources[]
| select(.type == "openstack_compute_instance_v2" and
.primary.attributes.name == "jumpbox").primary.id' terraform.tfstate
"5edfe2bf-94df-49d5-8118-3e91fb52946b"
$ jq '.modules[].resources[]
| select(.type =="openstack_compute_floatingip_associate_v2" and
.primary.attributes.instance_id == "5edfe2bf-94df-49d5-8118-3e91fb52946b").primary.attributes.floating_ip' terraform.tfstate
"10.120.241.21"
Giving me the external floating IP of the 'jumpbox' VM based on its name.
I'd like to make that all one jq call. Is that possible?
This would be easier to answer if you provided more sample data but
working backwards from your commands (with some reformatting)
$ jq '
.modules[].resources[]
| select(.type == "openstack_compute_instance_v2" and .primary.attributes.name == "jumpbox")
| .primary.id
' terraform.tfstate
"5edfe2bf-94df-49d5-8118-3e91fb52946b"
$ jq '
.modules[].resources[]
| select(.type =="openstack_compute_floatingip_associate_v2" and .primary.attributes.instance_id == "5edfe2bf-94df-49d5-8118-3e91fb52946b")
| .primary.attributes.floating_ip
' terraform.tfstate
"10.120.241.21"
we can infer you have data which looks like
{
"modules": [
{
"resources": [
{
"type": "openstack_compute_instance_v2",
"primary": {
"id": "5edfe2bf-94df-49d5-8118-3e91fb52946b",
"attributes": {
"name": "jumpbox"
}
}
},
{
"type": "openstack_compute_floatingip_associate_v2",
"primary": {
"attributes": {
"instance_id": "5edfe2bf-94df-49d5-8118-3e91fb52946b",
"floating_ip": "10.120.241.21"
}
}
}
]
}
]
}
The following filter demonstrates a solution using functions, variables and parenthesis ():
def get_primary_id($name):
select(.type == "openstack_compute_instance_v2"
and .primary.attributes.name == $name)
| .primary.id
;
def get_floating_ip($id):
select(.type =="openstack_compute_floatingip_associate_v2"
and .primary.attributes.instance_id == $id)
| .primary.attributes.floating_ip
;
.modules[]
| ( .resources[] | get_primary_id("jumpbox") ) as $id
| ( .resources[] | get_floating_ip($id) ) as $fip
| ($id, $fip)
if this filter is in filter.jq and data.json contains the sample data above
then
$ jq -M -f filter.jq data.json
produces the output:
"5edfe2bf-94df-49d5-8118-3e91fb52946b"
"10.120.241.21"

What is this mysterious jq failures?

I have seen this issue. I guess it’s related to special char. I’ve read the jq manual and quote the field but still fail, I tried both with/without the bracket
abc#uswest1aprod 13:49:59 ~
$ cat test | jq .
{
"bus_v320161103-12-00-44": {
"aliases": {
"bus_v3": {}
},
"mappings": {
"business": {
"dynamic": "strict",
"_all": {
"enabled": false
}
}
}
}
abc#uswest1aprod 13:52:33 ~
$ cat test | jq ."bus_v320161103-12-00-44"
jq: error: null and number cannot be subtracted
abc#uswest1aprod 13:53:09 ~
$ cat test | jq .["bus_v320161103-12-00-44"]
error: bus_v320161103 is not defined
.[bus_v320161103-12-00-44] 1 compile error
You need to quote your filter so it isn't interpreted by the shell...
$ jq '."bus_v320161103-12-00-44"' test
Without it, it's effectively being passed in like this:
.bus_v320161103-12-00-44
Which is accessing a field called bus_v320161103 and subtracting that by 12, then 00 then 44.

Resources