jq - nested dictionary parser and extract key - json

I am trying to parse with jq the following structure:
{
"a": {
"sensitive": false,
"type": "string",
"value": "mykeypair"
},
"b": {
"sensitive": false,
"type": "string",
"value": "123"
}
}
and get this as an output:
{
"a": "mykeypair",
"b": "123"
}
I would like the key and as a value, the value of the field 'value'.
Any idea?
Cheers,

If you're merely getting the value of every value in the root object, you could use map_values/1 to get those values.
map_values(.value)

I think this is what you are looking for:
[ to_entries[] | .value = .value.value ] | from_entries
A simpler way:
with_entries(.value |= .value)
Check the result here:
https://jqplay.org/s/uHqfdPoF3e

Related

jq: Map from nested JSON

I have the following JSON:
{
"A": {
"type": "string",
"value": "value_A"
},
"B": {
"type": "string",
"value": "value_B"
}
}
...and am trying to use JQ to result in the following:
Desired Output
{
"A": "value_A",
"B": "value_B"
}
...where the key takes the direct value of node.value.
My current attempt:
.[] | {value}
...returns the following:
{
"value": "value_A"
}
{
"value": "value_B"
}
How can I use JQ to produce the desired JSON?
You don't need with_entries.
map_values(.value)
Online demo
with_entries helps:
with_entries(.value |= .value)
which is short for to_entries | map(.value |= .value) | from_entries
to_entries transforms an object of form {a:b} into an array in the form [{key:a, value:b}], so in your example:
{
"key": "A",
"value": {
"type": "string",
"value": "value_A"
}
}
.value |= .value then assigns the content of .value.value to .value, leaving you with:
{
"key": "A",
"value": "value_A"
}
which is then converted to an object again by from_entries (repeated from above: with_entries(f) is equivalent to from_entries|map(f)|from_entries)
Your attempt
.[] | {value}
just misses the update assignment.
This will work as expected:
.[] |= .value
{
"A": "value_A",
"B": "value_B"
}
Demo
Use the function map_values():
map_values(.value)
It runs the filter passed as argument to each value of the input object, collects the results and associates them with the keys of the input object and returns an object.
Check it online.

JQ map objects to array

I have this input data:
[
{
"attributes": {
"created": "2021-10-18T12:02:39+00:00",
"enabled": true,
"expires": null,
"notBefore": null
},
"contentType": null,
"id": "https://kjkljk./secrets/-/1",
"managed": null,
"name": "pw",
"tags": {}
},
{
"attributes": {
"created": "2021-10-18T12:06:16+00:00",
"enabled": true,
"expires": null,
"notBefore": null
},
"contentType": "",
"id": "https://kjklj./secrets/-/2",
"managed": null,
"name": "pw",
"tags": {}
}
]
I need to use jq to extract the id values into a new array where enabled is set to true. this is what I have so far:
.[] | select(any(.attributes; .enabled== true)) | {id}
but it only results in this:
{
"id": "https://kjkljk./secrets/-/1"
}
{
"id": "https://kjklj./secrets/-/2"
}
how can i make these two objects into an array of strings instead?
[
"id": "https://kjkljk./secrets/-/1",
"id": "https://kjklj./secrets/-/2"
]
Use map instead of .[] to retain the array:
map(select(any(.attributes; .enabled)) | {id})
[
{"id": "https://kjkljk./secrets/-/1"},
{"id": "https://kjklj./secrets/-/2"}
]
Demo
Note that this produces an array of objects [{…},{…}], what I believe is what you asked for although in your desired output you are missing the curly object braces { }. To make an "array of strigs" instead, use .id instead of {id} like so
map(select(any(.attributes; .enabled)) | .id)
[
"https://kjkljk./secrets/-/1",
"https://kjklj./secrets/-/2"
]
Demo
(Also, you can use .enabled instead of .enabled == true)
Something like:
$ jq '[.[] | select(.attributes.enabled) | .id]' input.json
[
"https://kjkljk./secrets/-/1",
"https://kjklj./secrets/-/2"
]
This should work:
map(select(any(.attributes; .enabled == true)) | .id)
Explanation: Rather than splitting the array with .[], the map() function leaves the array structure intact but operates on the elements. Using .id rather than {id} avoids creating a dictionary for each selected value.
If I understand right, you could also replace any(.attributes; .enabled == true) with just .attributes.enabled == true.
Like already written in the answers, comments before, your wished output is not valid json.
So you have to options. I pasted your input file in SO-70302009.json
Wrap the id line as objects jq 'map({id: select(any(.attributes; .enabled)) | .id})' "./SO-70302009.json"
to get
[
{
"id": "https://kjkljk./secrets/-/1"
},
{
"id": "https://kjklj./secrets/-/2"
}
]
Make an array of ids jq '{ ids: map(select(any(.attributes; .enabled)) | .id) }' "./SO-70302009.json"
to get
{
"ids": [
"https://kjkljk./secrets/-/1",
"https://kjklj./secrets/-/2"
]
}

JQ: How do I replace keys and values based on regex match?

I have two questions:
How can I use jq to search for "name" fields that start with an underscore (like _RDS_PASSWORD) and remove the leading underscore (so it becomes RDS_PASSWORD)
How can I use jq for "name" fields that start with an underscore (like _RDS_PASSWORD) and pass the value of the value cGFzc3dvcmQK to be decoded via base64? (ex: "cGFzc3dvcmQK" | base64 --decode)
Input:
[
{
"name": "RDS_DB_NAME",
"value": "rds_db_name"
},
{
"name": "RDS_HOSTNAME",
"value": "rds_hostname"
},
{
"name": "RDS_PORT",
"value": "1234"
},
{
"name": "RDS_USERNAME",
"value": "rds_username"
},
{
"name": "_RDS_PASSWORD",
"value": "cGFzc3dvcmQK"
}
]
Desired output:
[
{
"name": "RDS_DB_NAME",
"value": "rds_db_name"
},
{
"name": "RDS_HOSTNAME",
"value": "rds_hostname"
},
{
"name": "RDS_PORT",
"value": "1234"
},
{
"name": "RDS_USERNAME",
"value": "rds_username"
},
{
"name": "RDS_PASSWORD",
"value": "password"
}
]
Q1
walk( if type=="object" and has("name") and .name[0:1] == "_"
then .name |= .[1:]
else .
end)
If your jq does not have walk/1 then you can either upgrade to a more recent version of jq than 1.5, or include its def, which can be found at https://github.com/stedolan/jq/blob/master/src/builtin.jq
Q2
.. | objects | select(has("name") and .name[0:1] == "_") | .value
If you are certain that the encoded string was a UTF-8 string, you could use jq's #base64d; otherwise, invoke jq with the -r option and pipe the results to a decoder as you indicated you planned to do.

How do I update a single value in a nested array of objects in a json document using jq?

I have a JSON document that looks like the following. Note this is a simplified example of the real JSON, which is included at bottom of question:
{
"some_array": [
{
"k1": "A",
"k2": "XXX"
},
{
"k1": "B",
"k2": "YYY"
}
]
}
I would like to change the value of all the k2 keys in the some_array array where the value of the k1 key is "B".
Is this possible using jq ?
For reference this is the actual JSON document, which is an environment variable file for use in postman / newman tool. I am attempting this conversion using JQ because the tool does not yet support command line overrides of specific environment variables
Actual JSON
{
"name": "Local-Stack-Env-Config",
"values": [
{
"enabled": true,
"key": "KC_master_host",
"type": "text",
"value": "http://localhost:8087"
},
{
"enabled": true,
"key": "KC_user_guid",
"type": "text",
"value": "11111111-1111-1111-1111-11111111111"
}
],
"timestamp": 1502768145037,
"_postman_variable_scope": "environment",
"_postman_exported_at": "2017-08-15T03:36:41.474Z",
"_postman_exported_using": "Postman/5.1.3"
}
Here is a slightly simpler version of zayquan's filter:
.some_array |= map(if .k1=="B" then .k2="changed" else . end)
Here's another solution.
jq '(.some_array[] | select(.k1 == "B") | .k2) |= "new_value"'
Output
{
"some_array": [
{
"k1": "A",
"k2": "XXX"
},
{
"k1": "B",
"k2": "new_value"
}
]
}
Here is a viable solution:
cat some.json | jq '.some_array = (.some_array | map(if .k1 == "B" then . + {"k2":"changed"} else . end))'
produces the output:
"some_array": [
{
"k1": "A",
"k2": "XXX"
},
{
"k1": "B",
"k2": "changed"
}
]
}

Using jq to select a parent by searching child key/value pair

Using jq, how do I select a parent object if it contains a child object that meets two filter requirements?
In this example I want to select all Subnets elements that have a child tag with key "Name" and value "TheName". My example has two subnets. The first has "TheName" in the wrong key. The second subnet has the name/value pair I am looking for. i.e. "Key": "Name", "Value": "TheName"
The following selects a subnet with the specified value in one of the tags but not the pair. It returns both subnets instead of only the second subnet.
jq '.Subnets[] | select(.Tags[].Value=="TheName")' output
How do I use jq to select only the subnets that have the name/value pair I am looking for?
{
"Subnets": [
{
"VpcId": "vpc-12345678",
"SubnetId": "subnet-1234567a",
"Tags": [
{
"Key": "IgnoreThis",
"Value": "TheName"
},
{
"Key": "Name",
"Value": "NotTheName"
}
]
},
{
"VpcId": "vpc-12345678",
"SubnetId": "subnet-1234567b",
"Tags": [
{
"Key": "IgnoreThis",
"Value": "ignore"
},
{
"Key": "Name",
"Value": "TheName"
}
]
}
]
}
The desired output would be:
{
"VpcId": "vpc-12345678",
"SubnetId": "subnet-1234567b",
"Tags": [
{
"Key": "IgnoreThis",
"Value": "ignore"
},
{
"Key": "Name",
"Value": "TheName"
}
]
}
Assuming your jq has any/2, a simple and efficient solution would be:
.Subnets[]
| select( any (.Tags[]; .Key == "Name" and .Value == "TheName") )
This produces the output you want, so I won't repeat it here.
If your jq does not have any/2, I'd suggest upgrading, but if that's inconvenient or not an option, you could use this def:
def any(f;g): reduce f as $i (false; . or ($i|g));
p.s. any(str; cond) can be read as: 'Is there any element, e, in the stream, str, such that e|cond has a value other than null or false?'
Here is a solution which uses indices
.Subnets[] | select(.Tags | indices({Key:"Name", Value:"TheName"}) != [])