jq - find parent element based on search result on child element - json

For the following json file I need to get 'name' element based on search results for that specific entry
eg: json.txt
{
"regions": {
"var1": {
"name": "City 1",
"domains": {
"var3": {
"Owner": "Joe"
}
}
},
"var2": {
"name": "City 2",
"domains": {
"var4": {
"Owner": "Brown"
}
}
}
}
}
I tried
$ jq --arg arg1 'var4' '.regions | if (to_entries[].value.domains[$arg1]) then to_entries[].value.name else empty end' json.txt
but that returns
"City 1"
"City 2"
I want the result to only fetch
"City 2"
Any assistance would be greatly appreciated

You need to pull to_entries[] outside the if ... then ... else ... end clause:
.regions | to_entries[] | if .value.domains[$arg1] then .value.name else empty end
This can be shortened to:
.regions | to_entries[] | .value | select(.domains[$arg1]) | .name

Related

Parsing json values using jq

I am trying to get values "en" of a JSON structure using jq on the linux command line.
find . -name "*.json" -exec jq -r \ '(input_filename | gsub("^\\./|\\.json$";"")) as $fname (map(.tags) | .[] | .[] | .tag.en ) as $tags | "\($fname)&\($tags)"' '{}' +
i have more than 5000 files, start from 0001.json 0002.json .. 5000.json
This is a simple file 0001.json
{
"result": {
"tags": [
{ "confidence": 100, "tag": { "en": "turbine" } },
{ "confidence": 64.8014373779297, "tag": { "en": "wind" } },
{ "confidence": 63.3033409118652, "tag": { "en": "generator" } },
{ "confidence": 7.27894926071167, "tag": { "en": "device" } },
{ "confidence": 7.01708889007568, "tag": { "en": "line" } }
]
},
"status": { "text": "", "type": "success" }
}
i get this result :
0001&turbine
0001&wind
0001&generator
0001&device
0001&line
jq: error (at ./0001.json:0): Cannot iterate over null (null)
Ouptut..
jq: error (at ./0002.json:0): Cannot iterate over null (null)
Output..
jq: error (at ./0003.json:0): Cannot iterate over null (null)
My Desired Output in one file from all json files results.
filename&enValue:confidenceValue
0001&turbine:100,wind:64,generator:63,device:7,line:7
0002&...
0003&...
0004&...
The jq filter you want can be written as follows:
(input_filename | gsub("^\\./|\\.json$";"")) as $fname
| ( [ .result.tags[] | [.tag.en, (.confidence | floor)] | join(":") ]
| join(",") ) as $tags
| "\($fname)&\($tags)"

Filter JSON in Powershell

I have the following JSON in a Powershell variable:
{
"Object1": {
"name": "asdf1",
"criteria": 2
},
"Object2": {
"name": "asdf2",
"criteria": 1
}
}
I want to get JSON where the value of criteria is 1. The result therefore should look as follows:
{
"Object2": {
"name": "asdf2",
"criteria": 1
}
}
I made an attempt with the following code:
$json | Get-ObjectMembers | Select-Object | where { $_.value.criteria -eq 1 };
While this basically goes into the right direction, it is not what I want exactly, because the result looks like this:
{
"name": "asdf2",
"criteria": 1
}
See that the Object2 information is lost and one depth-level is lost.
How can I achieve the desired result as shown above?
In essence, you're looking to only retain properties of interest from your single input object or, to put it differently, to remove properties you're not interested in.
Here's a PSv4+ solution:
$json = #'
{
"Object1": {
"name": "asdf1",
"criteria": 2
},
"Object2": {
"name": "asdf2",
"criteria": 1
}
}
'#
($json | ConvertFrom-Json).psobject.Properties.
Where({ $_.Value.criteria -eq 1 }).
ForEach({ [pscustomobject] #{ $_.Name = $_.Value } }) |
ConvertTo-Json
The above yields:
{
"Object2": {
"name": "asdf2",
"criteria": 1
}
}
The jq solution. with_entries temporarily turns a list of properties into key and value pairs. https://stedolan.github.io/jq/manual/#to_entries,from_entries,with_entries (section id's in html come in handy) (Json creators don't believe in arrays?)
$json = '{
"Object1": {
"name": "asdf1",
"criteria": 2
},
"Object2": {
"name": "asdf2",
"criteria": 1
}
}'
$json | jq 'with_entries(select(.value.criteria == 1))'
{
"Object2": {
"name": "asdf2",
"criteria": 1
}
}

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

Json search and print

I've been trying to use jq parser to help me extract information from json files.
Here is an example snippet
{
"main_attribute": {
"name": {
"display_name": "abc"
},
"address": {
"unit": "1",
"street": "Dundas",
"suburb": "Syd",
"state": "NSW"
},
"financial_debt": {
"bank_loan": true
}
},
"secondary_attr": {
"income": {
"pretax": 100000
},
"automobile": {
"make": "Citroen",
"model": 2015,
"new": true
},
"property": {
"property_owned": 1,
"owned_since": 2000,
"first_sale": true
},
"education": {
"degree": "MS",
"graduated": 1990,
"financial_debt": {
"bank_loan": false
}
}
}
}
I need to find the blocks where "financial_debt" is true. This field could be either in the main_attribute (as a global value) or in the secondary attribute.
Expected output:
financial_debt: bank_loan on "automobile" and "property"
Can you please advise how to go about doing this search using jq?
This is by no means the most efficient way, but it is functional. It returns a boolean value specifying whether or not there is a true boolean value under the financial_debt property.
jq '[recurse | .financial_debt? | select(. != null) | recurse | booleans] | any'
tostream can be used to find paths containing "financial_debt" as follows:
tostream
| select(length==2)
| select(.[0] | contains(["financial_debt"]))
with this filter in filter.jq and data in data.json
$ jq -M -c -f filter.jq data.json
produces
[["main_attribute","financial_debt","bank_loan"],true]
[["secondary_attr","education","financial_debt","bank_loan"],false]
This intermediate result can be used along with reduce, setpath, getpath and a filter such as
. as $d
| reduce ( tostream
| select(length==2)
| select(.[0] | contains(["financial_debt"]))) as [$p,$v] (
{}
; setpath($p[:-1]; $d | getpath($p[:-1]))
)
to produce
{
"main_attribute": {
"financial_debt": {
"bank_loan": true
}
},
"secondary_attr": {
"education": {
"financial_debt": {
"bank_loan": false
}
}
}
}

jq parsing json input with variables

I have this input:
{
"users": [
{
"name": "tester-01",
"user": {
"username": "tester01"
}
},
{
"name": "tester-02",
"user": {
"username": "tester02"
}
}
],
"current-user": "tester-02"
}
Using jq (1.5), I want to print the username that matches current-user.
Can anyone share how this would be done or tips to get me started?
This was my solution.
cat 99 | jq -r '."current-user" as $foo | .users[] | select(.name == $foo).user'
{
"username": "tester02"
}
The select solution is good. Here is an alternative that uses foreach.
foreach .users[] as $u (
."current-user"
; .
; if . == $u.name then $u.user.username else empty end
)