jq select items where a property contains the value of another property - json

I'm trying to filter for items from a list that contain the values of other properties in the same object.
Example of the data.json:
{ result:
[
{ name: 'foo', text: 'my name is foo' },
{ name: 'bar', text: 'my name is baz' },
]
}
What I've tried:
cat data.json | jq '.result[] | select(.text | ascii_downcase | contains(.name))'
However it throws the following error:
Cannot index string with string
Is there a way in jq to select based on a dynamic property rather than a string literal?

Assuming your JSON looks more like this (strings in double quotes, no comma after the last array item):
{ "result":
[
{ "name": "foo", "text": "my name is foo" },
{ "name": "bar", "text": "my name is baz" }
]
}
When going into .text, you have lost the context from which you can access .name. You could save it (or directly the desired value) in a variable and reference it when needed:
jq '.result[] | select(.name as $name | .text | ascii_downcase | contains($name))'
{
"name": "foo",
"text": "my name is foo"
}
Demo

Related

jq: map arrays to csv field headers

Is there a way to export a json like this:
{
"id":"2261026",
"meta":{
"versionId":"1",
"lastUpdated":"2021-11-08T15:13:39.318+01:00",
},
"address": [
"string-value1",
"string-value2"
],
"identifier":[
{
"system":"urn:oid:2.16.724.4.9.20.93",
"value":"6209"
},
{
"system":"urn:oid:2.16.724.4.9.20.2",
"value":"00042"
},
{
"system":"urn:oid:2.16.724.4.9.20.90",
"value":"UAB2"
}
]
}
{
"id":"2261027",
"meta":{
"versionId":"1",
"lastUpdated":"2021-11-08T15:13:39.318+01:00",
},
"address": [
"string-value1",
"string-value2",
"string-value3",
"string-value4"
],
"identifier":[
{
"system":"urn:oid:2.16.724.4.9.20.93",
"value":"6205"
},
{
"system":"urn:oid:2.16.724.4.9.20.2",
"value":"05041"
}
]
}
I'd like to get something like this:
"id","meta_versionId","meta_lastUpdated","address","identifier0_system","identifier0_value","identifier1_system","identifier1_value","identifier2_system","identifier2_value"
"2261026","1","2021-11-08T15:13:39.318+01:00","string-value1|string-value2","urn:oid:2.16.724.4.9.20.93","6209","urn:oid:2.16.724.4.9.20.2","00042","urn:oid:2.16.724.4.9.20.90","UAB2"
"2261027","1","2021-11-08T15:13:39.318+01:00","string-value1|string-value2|string-value3|string-value4","urn:oid:2.16.724.4.9.20.93","6205","urn:oid:2.16.724.4.9.20.2","05041",,
In short:
address array field string values has to be mapped joining its values using "|" character. Example: "string-value1|string-value2"
identifiers array field objects have to be mapped to "n-field-header". Example: "identifier0_system","identifier0_value","identifier1_system","identifier1_value","identifier2_system","identifier2_value,..."
Any ideas?
Try this
jq -r '[
.id,
(.meta | .versionId, .lastUpdated),
(.address | join("|")),
(.identifier[] | .system, .value)
] | #csv'
Demo
To prepend a header row with the number of identifierX_system and identifierX_value field pairs in it matching the length of the input's longest identifier array, try this
jq -rs '[
"id",
"meta_versionId", "meta_lastUpdated",
"address",
(
range([.[].identifier | length] | max)
| "identifier\(.)_system", "identifier\(.)_value"
)
], (.[] | [
.id,
(.meta | .versionId, .lastUpdated),
(.address | join("|")),
(.identifier[] | .system, .value)
]) | #csv'
Demo

jq: How to replace element in an array or add it if it doesn't exist

Given the following json structure:
{
"elements": [
{
"name": "disregard",
"value": "me"
},
{
"name": "foo",
"value": "bar"
},
{
"name": "dont-edit",
"value": "me"
}
]
}
What would be the appropriate jq query to replace the value of the name: foo element or create/add the element to the array, if it doesn't already exist?
Here is a safe if pedestrian solution:
.elements
|= (map(.name) | index("foo")) as $ix
| if $ix
then .[$ix]["value"] = "BAR"
else . + [{name: "foo", value: "BAR"}]
end
You might want to abstract away the "foo" and "BAR" bits:
upsert
# Input is assumed to be an array of {name:_, value:_} objects
def upsert($foo; $bar):
(map(.name) | index($foo)) as $ix
| if $ix then .[$ix]["value"] = $bar else . + [{name: $foo, value: $bar}] end;
Usage:
.elements |= upsert("foo"; "BAR")

Filter object or array

I would like to list all the Ids and roles in a given json but where there is only a single role, rather than an array of 1 it provides it as an object, so if I run "[]?" I get the error Cannot index string with string "Name".
Extract (example.json):
{
"Person": [
{
"Roles": {
"Role": {
"#Id": "1",
"Name": "Job1"
}
}
},
{
"Roles": {
"Role": [
{
"#Id": "2",
"Name": "Job2"
},
{
"#Id": "3",
"Name": "Job3"
}
]
}
}
]
}
I hoped this may work:
jq -r . | '.Roles.Role[]?>.#Id + "," + .Roles.Role[]?>.Name'
This is the output I'd like (so I can pipe to a csv)
1,Job1
2,Job2
3,Job3
The following produces the CSV shown below. It would be easy to tweak the program to remove the double-quotation marks, etc.
.Person[]
| .Roles.Role
| if type == "array" then .[] else . end
| [.["#Id"], .Name]
| #csv
Output
"1","Job1"
"2","Job2"
"3","Job3"
Adding the index in .Person
.Person
| range(0; length) as $ix
| .[$ix]
| .Roles.Role
| if type == "array" then .[] else . end
| [$ix, .["#Id"], .Name]
| #csv

Extract inner field value from JSON document based on a key using jq

I have a json file with the below format. I want to extract the name field value from inside based on the id value.
so, if I pass id value as 99900, it should return me DEF. How can I do that using jq.
{
"11213-99900": {
"cid": "11213-99900",
"name": "DEF",
"id": "99900"
},
"11213-12345": {
"cid": "11213-12345",
"name": "ABC",
"id": "12345"
},
"11272-23456": {
"cid": "11272-23456",
"name": "YXX",
"id": "23456"
}
}
Use select:
$ jq -r --arg q 99900 '.[] | select(.id == $q).name' file
DEF

how to select a json object where a child value array contains a certain propery

I have an array of objects similar to the following:
[
{
"id": "one",
"tags": {
"my.key": "true"
}
},
{
"id": "two",
}
]
How can I select all "id" values for each object containing a tag where "my.key" is "true"?
You can use a select with .tags["my.key"] == "true" and get only the id field :
jq '.[] | select(.tags["my.key"] == "true") | .id' data.json