How can I add entries to generated to_entries? - jq

I have this json:
{
"idTypes":"type1|type2|type3",
"idValues":"xxx|yyy|zzz"
}
I need to reshape this information to:
{
"idType": "type1",
"idValue": "xxxx"
}
{
"idType": "type2",
"idValue": "yyyy"
}
{
"idType": "type1",
"idValue": "zzzz"
}
Up to now I've tried with this (click jqplay here):
.idTypes| split("|") | to_entries[]
But it doesn't generate what I need:
{
"key": 0,
"value": "type1"
}
{
"key": 1,
"value": "type2"
}
{
"key": 2,
"value": "type3"
}
Any ideas?

to_entries | map(.value | split("|")) | transpose[] | {"idType": .[0], "idValue": .[1] }
Will generate
{
"idType": "type1",
"idValue": "xxx"
}
{
"idType": "type2",
"idValue": "yyy"
}
{
"idType": "type3",
"idValue": "zzz"
}
Online demo.
Regarding transpose please read jq's docs about this.

Related

Conditional append a element to an array

Here is the jq I have, it just wants to build a new element and then append it to an array,
[.[] | . as { foo: $foo1, bar: $bar1} |
{
names: ([
$foo1 | range(0;length) as $i |
{ key: ($foo1[$i]) }
] + [{ key: $bar1 }])
} |
{
values: .names,
}
]
And suppose I have a json like this,
{
"foo":[
"key1",
"key2"
],
"bar": "key3"
}
This will generate a json file like this,
[
{
"values": [
{
"key": "key1"
},
{
"key": "key2"
},
{
"key": "key3"
}
]
}
]
But the element should be only appended when the $bar is not an empty string, can I do something like this?
[.[] | . as { foo1: $foo1, bar1: $bar1 if $bar != ""}
...
or do it when is appended,
names: ([
$foo1 | range(0;length) as $i |
{ key: ($foo1[$i]) }
] + [{ key: $bar1 }] | if $bar != "")
thanks in advance for any help!
You could just use select to filter out that case
jq '[{values: (.foo + [.bar | select(. != "")]) | map({key:.})}]'
If .bar == "key3", it prints
[
{
"values": [
{
"key": "key1"
},
{
"key": "key2"
},
{
"key": "key3"
}
]
}
]
If .bar == "", it prints
[
{
"values": [
{
"key": "key1"
},
{
"key": "key2"
}
]
}
]
If .bar does not exist, it will print
[
{
"values": [
{
"key": "key1"
},
{
"key": "key2"
},
{
"key": null
}
]
}
]
If in this last case you want to have the same result as with .bar == "", then change . != "" to values != "" in the filter to consider only values that are not null (or to strings != "" to only consider (non-empty) strings and disregard any other type).

jq: filter nested array objects

Here my documents:
[
{
"id": "3e67b455-8cdb-4bc0-a5e1-f90253870fc9",
"identifier": [
{
"system": {
"value": "urn:oid:2.16.724.4.9.20.91-INVENTAT"
},
"value": {
"value": "04374"
}
},
{
"system": {
"value": "urn:oid:2.16.724.4.9.20.2-INVENTAT"
},
"value": {
"value": "INFP3"
}
},
{
"system": {
"value": "urn:oid:INVENTAT"
},
"value": {
"value": "CBOU035"
}
}
]
},
{
"id": "0f22e5ff-70bc-457f-bdaf-7afe86d478de",
"identifier": [
{
"system": {
"value": "urn:oid:2.16.724.4.9.20.91-INVENTAT"
},
"value": {
"value": "04376"
}
},
{
"system": {
"value": "urn:oid:2.16.724.4.9.20.2-INVENTAT"
},
"value": {
"value": "INF07"
}
},
{
"system": {
"value": "urn:oid:INVENTAT"
},
"value": {
"value": "S527918"
}
}
]
},
{
"id": "a1ea574c-438b-443c-ad87-d31d09d581f0",
"identifier": [
{
"system": {
"value": "urn:oid:2.16.724.4.9.20.91-INVENTAT"
},
"value": {
"value": "08096"
}
},
{
"system": {
"value": "urn:oid:2.16.724.4.9.20.2-INVENTAT"
},
"value": {
"value": "INF04"
}
},
{
"system": {
"value": "urn:oid:INVENTAT"
},
"value": {
"value": "5635132"
}
}
]
}
]
I need to filter .identifier where system.value="urn:oid:2.16.724.4.9.20.91-INVENTAT" or system.value="urn:oid:2.16.724.4.9.20.2-INVENTAT" and pick .value.value.
Desired output:
[
{
"id": "3e67b455-8cdb-4bc0-a5e1-f90253870fc9",
"oid1": "04374",
"oid2": "INFP3"
},
{
"id": "0f22e5ff-70bc-457f-bdaf-7afe86d478de",
"oid1": "04376",
"oid2": "INF07"
},
{
"id": "a1ea574c-438b-443c-ad87-d31d09d581f0",
"oid1": "08096",
"oid2": "INF04"
}
]
I've tried:
map(
{
id,
oid1: select(.identifier?[]?.system.value == "urn:oid:2.16.724.4.9.20.91-INVENTAT") | .identifier[].value.value,
oid2: select(.identifier?[]?.system.value == "urn:oid:2.16.724.4.9.20.2-INVENTAT") | .identifier[].value.value
}
)
But output is not what I need: you can find it on this jqplay.
Any ideas?
This uses IN to check for your query strings, and with_entries on an array to generate the indeces for the oid keys.
jq '
map({id} + (.identifier | map(select(IN(.system.value;
"urn:oid:2.16.724.4.9.20.91-INVENTAT",
"urn:oid:2.16.724.4.9.20.2-INVENTAT"
)).value.value) | with_entries(.key |= "oid\(. + 1)")))
'
[
{
"id": "3e67b455-8cdb-4bc0-a5e1-f90253870fc9",
"oid1": "04374",
"oid2": "INFP3"
},
{
"id": "0f22e5ff-70bc-457f-bdaf-7afe86d478de",
"oid1": "04376",
"oid2": "INF07"
},
{
"id": "a1ea574c-438b-443c-ad87-d31d09d581f0",
"oid1": "08096",
"oid2": "INF04"
}
]
Demo
Here is a ruby to do that:
ruby -r json -e '
def walk(x, filt)
rtr=[]
rep=["uab", "ub"]
x.each{|e|
rd={"id"=>e["id"]}.merge(
e["identifier"].
filter{|ea| filt.include?(ea["system"]["value"])}.
map.with_index(1){|di, i| ["#{rep[i%2]}", "#{di["value"]["value"]}"]}.to_h)
rtr << rd
}
rtr
end
data=JSON.parse($<.read)
puts walk(data, ["urn:oid:2.16.724.4.9.20.91-INVENTAT", "urn:oid:2.16.724.4.9.20.2-INVENTAT"]).to_json
' file
Prints:
[{"id":"3e67b455-8cdb-4bc0-a5e1-f90253870fc9","ub":"04374","uab":"INFP3"},{"id":"0f22e5ff-70bc-457f-bdaf-7afe86d478de","ub":"04376","uab":"INF07"},{"id":"a1ea574c-438b-443c-ad87-d31d09d581f0","ub":"08096","uab":"INF04"}]

Parsing on jq with_entries

I have the following data
Command output:
| jq '.rrsets[]'
{
"comments": [],
"name": "name1.",
"records": [
{
"content": "10.10.10.10",
"disabled": false
}
],
"ttl": 60,
"type": "A"
}
{
"comments": [],
"name": "name2.",
"records": [
{
"content": "20.20.20.20",
"disabled": false
}
],
"ttl": 60,
"type": "CNAME"
}
I want to get names where type is A.
Help, tell me how to do this?
| jq '.rrsets[] | with_entries(select(.key== "name", .value == "A"))'
{
"name": "name1."
}
{
"name": "name2.",
"type": "A"
}
Displays all the lines, but I only need where type = A
I'm not sure if this is what you are looking for, but wouldn't simply ... | select(.type == "A") do the trick?
... | jq '.rrsets[] | select(.type == "A")'
{
"comments": [],
"name": "name1.",
"records": [
{
"content": "10.10.10.10",
"disabled": false
}
],
"ttl": 60,
"type": "A"
}
Demo
And then just get the .name if you want only that (using -r to get rid of the JSON formatting):
... | jq -r '.rrsets[] | select(.type == "A").name'
name1.
Demo

Replace values inside list

I have the following object :
{
"db_credentials": {
"database": "greengrass",
"host": "localhost",
"password": "yZqXJzXHLUsLlPm",
"port": 7086,
"username": "greengrass"
},
"default_interval": 90000,
"fields_selected": [
{
"measurement": "ABPLCGD-GD_AB1AirFlowCalc",
"aggregation": "last",
"step": "10m",
"timeserie_physical": "null",
"timeserie_type": "null",
"timeserie_interpolation": "null",
"timeserie_unit": "null",
"timeserie_step": "10"
},
{
"measurement": "ABPLCGD-GD_AB1InletAirTempAct",
"aggregation": "last",
"step": "10m",
"timeserie_physical": "null",
"timeserie_type": "null",
"timeserie_interpolation": "null",
"timeserie_unit": "null",
"timeserie_step": "10"
}
]
}
and i wish to transform it into :
{
"db_credentials": {
"database": "greengrass",
"host": "localhost",
"password": "yZqXJzXHLUsLlPm",
"port": 7086,
"username": "greengrass"
},
"default_interval": 90000,
"fields_selected": [
{
"name": "ABPLCGD-GD_AB1AirFlowCalc",
"aggregation": {
"step": "10m",
"function": "last"
}
},
{
"name": "ABPLCGD-GD_AB1InletAirTempAct",
"aggregation": {
"step": "10m",
"function": "last"
}
}
]
}
i have tried multiple solution but this is the maximum where i can get :
jq ' .fields_selected = .fields_selected | map({name : .measurement , aggregation : {step: .step , function: .aggregation}})' config-it-client.json
but i got always this error that Cannot index number with string "measurement" and i cant figure out what i'm doing wrong
I'd use the following:
.fields_selected[] |= { name: .measurement, aggregation: { function: .aggregation, step } }
To get it working, you were just missing parens.
.fields_selected = .fields_selected | ...
means
( .fields_selected = .fields_selected ) | ...
It should be
.fields_selected = ( .fields_selected | ... )
This gives us
.fields_selected = (
.fields_selected |
map({
name: .measurement,
aggregation: {
function: .aggregation,
step: .step
}
})
)
Demo on jqplay
But we can improve this. foo = ( foo | ... ) can generally be written as foo |= ( ... ).
.fields_selected |= map({
name: .measurement,
aggregation: {
function: .aggregation,
step: .step
}
})
We could modify the objects in the fields array instead of the array itself.
.fields_selected[] |= {
name: .measurement,
aggregation: {
function: .aggregation,
step: .step
}
}
Finally, { foo: .foo, ... } can be shortened to { foo, ... }.
.fields_selected[] |= {
name: .measurement,
aggregation: {
function: .aggregation,
step
}
}
As a sh one-liner:
jq '.fields_selected[] |= { name: .measurement, aggregation: { function: .aggregation, step } }'
Demo on jqplay
I was able to figure out what i was doing wrong:
jq '.fields_selected = (.fields_selected | map({name : .measurement , aggregation : {step: .step , function: .aggregation}}))' config-it-client.json

Reporting every (optional) subelement

Want to parse the following:
{
"issues": [
{ "id": "1", "fields": { "links": [] } },
{ "id": "2", "fields": { "links": [ { "inlink": { "id": "red" } } ] } },
{ "id": "3", "fields": { "links": [ { "outlink": { "id": "yellow" } } ] } },
{ "id": "4", "fields": { "links": [ { "inlink": { "id": "green" } }, { "outlink": { "id": "blue" } } ] } }
]
}
into elements that represent the links elements, one for one, like this (note that id 1 is missing and id 4 appears twice:
{ "id": "2", "link": { "linktype": "inlink", "id": "red" } },
{ "id": "3", "link": { "linktype": "outlink", "id": "yellow" } },
{ "id": "4", "link": { "linktype": "inlink", "id": "green" } },
{ "id": "4", "link": { "linktype": "outlink", "id": "blue" } }
The following jq works for inlink or outlink separately
.issues[] | .id as $id | .fields.links[] | .inlink.id as $lid | {$id,$lid}
giving
{ "id": "2", "lid": "red" }
{ "id": "3", "lid": null }
{ "id": "4", "lid": "green" }
{ "id": "4", "lid": null }
but can't figure out how to track both types simultaneously or introduce the key linktype. Any ideas?
jq solution:
jq -c '.issues[] | .id as $id
| .fields.links[] | to_entries[]
| {"id": $id, "link": {"linktype": .key, "id": .value.id}}' file
The output:
{"id":"2","link":{"linktype":"inlink","id":"red"}}
{"id":"3","link":{"linktype":"outlink","id":"yellow"}}
{"id":"4","link":{"linktype":"inlink","id":"green"}}
{"id":"4","link":{"linktype":"outlink","id":"blue"}}

Resources