jq filtering with certain key value - json

I'm trying to get data with certain value. ex when device value is 10, get serialID qwer1234.
I have tried jq-win64 -c ".devices[].serialID | select(.devices.device == 10)" and I get error
jq: error (at C:\test.json:60): Cannot index string with string "devices"
I'm using jq1.6 on windows 10.
{
"devices": [
{
"device": 10,
"serialID": "qwer1234",
},
{
"device": 20,
"serialID": "q1w2e3r4",
},
{
"device": 30,
"serialID": "wasd1234",
}
]

The appropriate jq query is:
.devices[] | select(.device == 10).serialID
However this assume the input is valid JSON.

Related

How to perform a check on multiple sub-trees

What I'm trying to do currently, is, within each environment, compare mainAccount and secondAccount values.
If they do match, then I will trigger some downstream code to check the file version. If they do not, then I will pass. That is not really relevant, however I am struggling to compare the values across each environment. Since each .json file will have different amounts of environments.
Meaning, in testing environment, I want to check if mainAccount = secondAccount, and same in production environment.
I'm running into issues parsing this JSON with jq:
json1
{
"file_version": 1.0,
"config": [
{
"environment": "testing",
"main": [
{
"mainAccount": "123"
}
],
"second": [
{
"secondAccount": "456"
}
]
},
{
"environment": "production",
"main": [
{
"mainAccount": "789"
}
],
"second": [
{
"secondAccount": "789"
}
]
}
]
}
Here's another sample .json file for comparsion:
json2
{
"file_version": 1.3,
"config": [
{
"environment": "testing",
"main": [
{
"mainAccount": "123"
}
],
"second": [
{
"secondAccount": "456"
}
]
},
{
"environment": "production",
"main": [
{
"mainAccount": "789"
}
],
"second": [
{
"secondAccount": "789"
}
]
},
{
"environment": "pre-production",
"main": [
{
"mainAccount": "456"
}
],
"second": [
{
"secondAccount": "789"
}
]
},
{
"environment": "staging",
"main": [
{
"mainAccount": "234"
}
],
"second": [
{
"secondAccount": "456"
}
]
}
]
}
If I run this command:
jq -r '.config[] | select(.main != null) | .main[].mainAccount
My output is:
123
789
If i store this output in a variable, it'll be 123 789 so comparing this to the "secondAccount" value is troublesome.
I think what I'm looking for is iteration here, however, I'm not sure how to implement this. I wanted to take a pythonic approach to check the length of the config array, create a for loop in that length range, then collect the value based on an index like
.config[0] | select(.main != null) | .main[].mainAccount
.config[1] | select(.main != null) | .main[].mainAccount
etc. The issue however, is that when I read in the .config[] value as a variable, bash doesn't interpret it like that. The length will be the length of characters, not, the amount of objects in the array.
EXPECTED OUTPUT
Nothing. I simply want to, for each .json file above, compare the mainAccount and secondAccount values with eachother, within each environment.
In json1, I want to compare mainAccount == secondAccount in environment: testing. Then mainAccount == secondAccount in environment: production.
Then move onto json 2 and compare mainAccount == secondAccount in environment: testing. Then environment production, pre-production, staging, so on and so forth.
Since all information is within this one JSON file it is better to do the processing in jq as much as possible and to keep the shell out.
Given your input you can try this jq:
jq '
.config[]
| {
environment,
condition: (.main[0].mainAccount == .second[0].secondAccount)
}' input.json
The result is:
{
"environment": "testing",
"condition": false
}
{
"environment": "production",
"condition": true
}
Some questions though:
Why are the values of first and second arrays objects and not object?
Is it really intended to match the first one of both?
Can there be more items in the arrays?
Also: If you want to process the results in a shell, I propose this expression because the output can be used (source or eval) in a shell:
jq -r '
.config[]
| "\(.environment)=\(.main[0].mainAccount == .second[0].secondAccount)"' input.json
The output is:
testing=false
production=true
You can do the comparison within jq, return the boolean result as its exit status using the -e option, and react upon that in bash, e.g. using an if statement.
if jq -e '
.config | map(select(.main != null) | .main[].mainAccount) | .[0] == .[1]
' file.json >/dev/null
then echo "equal"
else echo "not equal"
fi
not equal

sort_by on array elements gives error 'Cannot index string with string "key"'

I'm trying to get the status of a code scan by the pull request ID and I'm having trouble getting the value of the status.
The json file looks similar to below.
{
"pullRequests": [
{
"key": "11346",
"title": "feature/XXX-Validation",
"branch": "feature/XXX-Validation",
"base": "develop",
"status": {
"qualityGateStatus": "OK",
"bugs": 0,
"vulnerabilities": 0,
"codeSmells": 1
},
"analysisDate": "2020-07-27T14:22:36+0000",
"url": "https://abc/org/_git/repo/pullrequest/11346",
"target": "develop"
},
{
"key": "11151",
"title": "feature/xxx-data",
"branch": "feature/xxx-data",
"base": "develop",
"status": {
"qualityGateStatus": "OK",
"bugs": 0,
"vulnerabilities": 0,
"codeSmells": 0
},
"analysisDate": "2020-07-22T11:11:11+0000",
"url": "https://abc/org/_git/repo/pullrequest/11151",
"target": "develop"
}
]
}
I need to sort this json by the key value (as this is the easiest way - earlier I had tried sorting by analysisDate) and get the value of qualityGateStatus for that key.
I tried this command to first sort by the key or analysisDate and then tried using key, but I keep getting the error. I thought maybe the value is not a string, so tried to map the key tonumber, but still doesn't work.
jq: error (at <stdin>:0): Cannot index string with string
Commands tried:
jq '.pullRequests[] |sort_by(.analysisDate)[-1].key'
jq '.pullRequests[] | sort_by(.key|tonumber)'
Error:
jq: error (at :0): Cannot index string with string "key"
The built-in sort_by accepts an array as input, not a stream of objects. You need to do:
jq '.pullRequests | sort_by(.key)'
If, as indicated in the comments, the actual goal is essentially to find the maximum value by .key, then it would be better to use max_by rather than sort_by. Based on the comments, the following would suffice:
.pullRequests
| max_by(.key).status.qualityGateStatus

Using jq to search value of a property and return another value

Sorry if this sounds too simple but I am still learning and have spent few hours to get a solution. I have a large json file and I would like to search a specific value from an object and return value from other object.
Example, from the below data, I would like to search the json file for all objects that have value in unique_number that match "123456" and return this value along with the IP address.
jq should return something like - 123456, 127.0.0.1
Since the file is going to be about 300 MB with many IP addresses will there be any performace issues?
Partial json -
{
"ip": "127.0.0.1",
"data": {
"tls": {
"status": "success",
"protocol": "tls",
"result": {
"handshake_log": {
"server_hello": {
"version": {
"name": "TLSv1.2",
"value": 1111
},
"random": "dGVzdA==",
"session_id": "dGVzdA==",
"cipher_suite": {
"name": "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
"value": 1122
},
"compression_method": 0,
},
"server_certificates": {
"certificate": {
"raw": "dGVzdA==",
"parsed": {
"version": 3,
"unique_number": "123456",
"signature_algorithm": {
"name": "SHA256-RSA",
"oid": "1.2.4.5.6"
},
The straight-forward way would be to use the select filter (either standalone on multiple values or with map on an array) and filter all objects matching your criterion (e.g. equal to "123456") and then transform into your required output format (e.g. using string interpolation).
jq -r '.[]
| select(.data.tls.result.handshake_log.server_certificates.certificate.parsed.unique_number=="123456")
| "\(.ip), \(.data.tls.result.handshake_log.server_certificates.certificate.parsed.unique_number)"'
Because the unique_number property is nested quite deeply and cumbersome to write twice, it makes sense to first transform your object into something simpler, then filter, and finally output in the desired format:
jq -r '.[]
| { ip, unique_number: .data.tls.result.handshake_log.server_certificates.certificate.parsed.unique_number }
| select(.unique_number=="123456")
| "\(.ip), \(.unique_number)"'
Alternatively using join:
.[]
| { ip, unique_number: .data.tls.result.handshake_log.server_certificates.certificate.parsed.unique_number }
| select(.unique_number=="123456")
| [.ip, .unique_number]
| join(", ")

JQ newbie trouble selecting nested keys

Hi I am new to JQ and Json. I am using
$ jq --version
jq-1.5
I am having a heck of a time trying to figure out how to select the values for id, attributes.name, attributes.albumName, and attributes.artistName
I am using the terminal app on a mac. I am running into some sort strange parsing problem
$ jq '.results.songs.data[0] | {id, attributes.name } ' t
jq: error: syntax error, unexpected FIELD, expecting '}' (Unix shell quoting issues?) at <top-level>, line 1:
.results.songs.data[0] | {id, attributes.name }
jq: 1 compile error
$
This example shows the structure of the data I am trying to filter looks like
$ jq '.results.songs.data[0] | {id, attributes } ' t
{
"id": "152471393",
"attributes": {
"previews": [
{
"url": "https://audio-ssl.itunes.apple.com/apple-assets-us-std-000001/AudioPreview71/v4/7d/c5/68/7dc56849-29b8-bd90-2bb1-51750e479569/mzaf_4742389090778091050.plus.aac.p.m4a"
}
],
"artwork": {
"width": 1449,
"height": 1449,
"url": "https://is5-ssl.mzstatic.com/image/thumb/Music/v4/7d/01/56/7d0156be-12cd-8724-a0ca-727b1013a81d/source/{w}x{h}bb.jpeg",
"bgColor": "ddcfc4",
"textColor1": "010100",
"textColor2": "422f10",
"textColor3": "2d2a27",
"textColor4": "614f34"
},
"artistName": "Gnarls Barkley",
"url": "https://itunes.apple.com/us/album/crazy/152471339?i=152471393",
"discNumber": 1,
"genreNames": [
"Alternative",
"Music",
"R&B/Soul",
"Rock",
"Soul",
"Hip-Hop/Rap",
"Rap",
"Hip-Hop",
"Adult Alternative",
"Neo-Soul",
"Alternative Rap",
"Underground Rap"
],
"durationInMillis": 178387,
"releaseDate": "2006-03-13",
"name": "Crazy",
"isrc": "USAT20611041",
"albumName": "St. Elsewhere",
"playParams": {
"id": "152471393",
"kind": "song"
},
"trackNumber": 2
}
}
Thanks
Andy
With your sample JSON as input, the following invocation:
jq '{id, name: .attributes.name }' input.json
produces:
{
"id": "152471393",
"name": "Crazy"
}
The filter above is short for:
{"id" : .id, "name": .attributes.name }
In any case, the keys must be appropriately specified.
For future reference, when asking questions on stackoverflow.com, please adhere to the http://stackoverflow.com/help/mcve guidelines as much as possible.

jq: How to match one of array and get sibling value

I have some JSON like this:
{
"x": [
{
"name": "Hello",
"id": "211"
},
{
"name": "Goodbye",
"id": "221"
},
{
"name": "Christmas",
"id": "171"
}
],
"y": "value"
}
Using jq, given a name value (e.g. Christmas) how can I get it's associated id (i.e. 171).
I've got as far as being able to check for presence of the name in one of the array's objects, but I can't work out how to filter it down
jq -r 'select(.x[].name == "Christmas")'
jq approach:
jq -r '.x[] | select(.name == "Christmas").id' file
171
The function select(boolean_expression) produces its input unchanged if boolean_expression returns true for that input, and produces no output otherwise.
It can also been done like:
jq '.x[] | select(.name == "Christmas").id'
Also you can try this at link online jq play