I am having trouble generating command regarding following json file I have - json

This is how my json file looks
"Patient":{
"Name":{
"Patient First Name":"James",
"Patient Middle Name":"Adam",
"Patient Last Name":"Manchester"
},
"Unique ID":163983,
"Demographics":{
"Sex":"M",
"Birthdate":"7/24/1940"
},
"IntakeCriteria":{
"DmDxDate":"8/25/2012",
"InitialHgbA1c":8.1,
"Comorbidity":["Diabetes Mellitus","CHF","DVT"]
},
"Labs":{
"LDLCholesterol":{
"LDLResultDate":"5/6/2013",
"LDLLevel":200
},
"SerumCreatinine":{
"CreatinineResultDate":"11/1/2016",
"CreatinineLevel":0.9
}
},
"CareLocation":{
"Facility Name":"East Side Clinic",
"Facility Contact Name":"Mary Silverman",
"Facility Contact Phone":"618-348-1891"
}
}
}
I need to prepare a query using the following fields:
Patient Unique ID number.
Patient First Name.
Patient Last Name.
Lab Test Date.
HgbA1c Level.
LDL Level.
Creatinine Level.
I tried this resulting in no result
jq - r’[.Patient.UniqueID, .Patient.Name.FirstName, .Patient.Name.LastName, .Patient.Labs.LDLCholesterol.LabResultDate, .Patient.IntakeCriteria.InitialHgbA1c, .Patient.Labs.LDLCholesterol.LDLLevel, .Patient.Labs.SerumCreatine.CreatineLevel] | #csv’ data.json > csvtest.out

When using object identifiers, you have to provide the field names exactly as used in the JSON file. Also, if they contain special characters such as white spaces (or start with a digit), surround them with double quotes for clarification:
jq -r '[
.Patient."Unique ID",
.Patient.Name."Patient First Name",
.Patient.Name."Patient Last Name",
.Patient.Labs.LDLCholesterol.LDLResultDate,
.Patient.IntakeCriteria.InitialHgbA1c,
.Patient.Labs.LDLCholesterol.LDLLevel,
.Patient.Labs.SerumCreatinine.CreatinineLevel
] | #csv' data.json > csvtest.out
163983,"James","Manchester","5/6/2013",8.1,200,0.9
Demo
To shorten your filter a bit, you may also group together some of the paths sharing common parents using subfilters with pipes | within a grouping with parentheses ():
jq -r '[.Patient |
."Unique ID",
(.Name | ."Patient First Name", ."Patient Last Name"),
.Labs.LDLCholesterol.LDLResultDate,
.IntakeCriteria.InitialHgbA1c,
(.Labs | .LDLCholesterol.LDLLevel, .SerumCreatinine.CreatinineLevel)
] | #csv' data.json > csvtest.out
163983,"James","Manchester","5/6/2013",8.1,200,0.9
Demo

Related

How do I print a specific value of an array given a condition in jq if there is no key specified

I am trying to output the value for .metadata.name followed by the student's name in .spec.template.spec.containers[].students[] array using the regex test() function in jq.
I am having trouble to retrieve the individual array value since there is no key specified for the students[] array.
For example, if I check the students[] array if it contains the word "Jeff", I would like the output to display as below:
student-deployment: Jefferson
What i have tried:
I've tried the command below which somewhat works but I am not sure how to get only the "Jefferson" value. The command below would print out all of the students[] array values which is not what I want. I am using Powershell to run the command below.
kubectl get deployments -o json | jq -r '.items[] | select(.spec.template.spec.containers[].students[]?|test("\"^Jeff.\"")) | .metadata.name, "\":\t\"", .spec.template.spec.containers[].students'
Is there a way to print a specific value of an array given a condition in jq if there is no key specified? Also, would the solution work if there are multiple deployments?
The deployment template below is in json and I shortened it to only the relevant parts.
{
"apiVersion": "v1",
"items": [
{
"apiVersion": "apps/v1",
"kind": "Deployment",
"metadata": {
"name": "student-deployment",
"namespace": "default"
},
"spec": {
"template": {
"spec": {
"containers": [
{
"students": [
"Alice",
"Bob",
"Peter",
"Sally",
"Jefferson"
]
}
]
}
}
}
}
]
}
For this approch, we introduce a variable $pattern. You may set it with --arg pattern to your regex, e.g. "Jeff" or "^Al" or "e$" to have the student list filtered by test, or leave it empty to see all students.
Now, we iterate over all .item[] elements (i.e. over "all deployments"). For each found, we output the content of .metadata.name followed by a literal colon and a space. Then we iterate again over all .spec.template.spec.containers[].students[], perform the pattern test and concatenate the outcome.
To print out raw strings instead of JSON, we use the -r option when calling jq.
kubectl get deployments -o json \
| jq --arg pattern "Jeff" -r '
.items[]
| .metadata.name + ": " + (
.spec.template.spec.containers[].students[]
| select(test($pattern))
)
'
To retrieve the "students" array(s) in the input, you could use this filter:
.items[]
| paths(objects) as $p
| getpath($p)
| select( objects | has("students") )
| .students
You can then add additional filters to select the particular student(s) of interest, e.g.
| .[]
| select(test("Jeff"))
And then add any postprocessing filters, e.g.
| "student-deployment: \(.)"
Of course you can obtain the students array in numerous other ways.

Search and extract value using JQ command line processor

I have a JSON file very similar to the following:
[
{
"uuid": "832390ed-58ed-4338-bf97-eb42f123d9f3",
"name": "Nacho"
},
{
"uuid": "5b55ea5e-96f4-48d3-a258-75e152d8236a",
"name": "Taco"
},
{
"uuid": "a68f5249-828c-4265-9317-fc902b0d65b9",
"name": "Burrito"
}
]
I am trying to figure out how to use the JQ command line processor to first find the UUID that I input and based on that output the name of the associated item. So for example, if I input UUID a68f5249-828c-4265-9317-fc902b0d65b9 it should search the JSON file, find the matching UUID and then return the name Burrito. I am doing this in Bash. I realize it may require some outside logic in addition to JQ. I will keep thinking about it and put an update here in a bit. I know I could do it in an overly complicated way, but I know there is probably a really simple JQ method of doing this in one or two lines. Please help me.
https://shapeshed.com/jq-json/#how-to-find-a-key-and-value
You can use select:
jq -r --arg query Burrito '.[] | select( .name == $query ) | .uuid ' tst.json

Get json object that has latest timestamp using jq

I have a below json file but I'm struggling to only display the description with the latest createdDate.
I tried with
>
<
todateiso8601?
now
and a few more but I can't get this to work.
Would anyone be able to help?
JSON:
{
"items": [
{
"createdDate": 1543585940,
"id": "awefef",
"description": "this is description 1"
},
{
"createdDate": 1555324487,
"id": "hjkvhuk",
"description": "this is description 2"
},
{
"createdDate": 1547034297,
"id": "xdfxdfv",
"description": "this is description 3"
}
]
}
Simply sort by .createdDate and (assuming you only want one value even if there is more than one with the greatest .createdDate value), select the last one:
.items
| sort_by(.createdDate)[-1].description
Ties
If you want all the descriptions in the case of ties:
.items
| sort_by(.createdDate)
| (.[-1].createdDate) as $max
| .[]
| select($max == .createdDate)
| .description
EDIT: use peaks answer it is superior
Here is a simple script that does this in 2 commands. Probably can be done in 1 but alas my nooblet skills were not enough
You can pipe to max with an array of numbers in JQ and it will return the largest value in the input array.
Then we use select to grab the object containing the max value and output the description.
We will also use arg which allows us to reference a local environment variable, and we need to cast it to a number or JQ thinks it's a string.
maxDate=$(cat tmp.json | jq '[.items[].createdDate] | max')
cat tmp.json | jq --arg maxDate "$maxDate" '.[][] | select(.createdDate == ($maxDate | tonumber)).description'
Output:
"this is description 2"
In the future, please post your desired output as well as your question so responders can be confident they are solving the problem to your liking

jq select error: "Cannot index string with string <object>"

command:
cat test.json | jq -r '.[] | select(.input[] | .["$link"] | contains("randomtext1")) | .id'
I was expecting to have both entries (a and b) to show up since they both contains randomtext1
Instead, I got the following output message:
a
jq: error (at <stdin>:22): Cannot index string with string "$link"
From some digging I understand that the issue is likely caused by the following object/value pair in the a entry:
"someotherobj": "123"
because it does not contain the object $link and the filter in the command expects to see $link in all objects under the input so it errors out before the command has a chance to search in the b entry.
What I really want is to be able to search for any entries that have at least one "$link": "randomtext1" pair under input. Is there a fuzzier search feature allowing me to achieve this?
I tried to use two contains hoping it will just pipe things through:
jq -r '.[] | select(.input[] | contains(["$link"]) | contains("randomtext1")) | .id'
but it did not like that at all..
the test.json file:
[
{
"input": {
"obj1": {
"$link": "randomtext1"
},
"obj2": {
"$link": "randomtext2"
},
"someotherobj": "123"
},
"id": "a"
},
{
"input": {
"obj3": {
"$link": "randomtext1"
},
"obj4": {
"$link": "randomtext2"
}
},
"id": "b"
}
]
What I really want is to be able to search for any entries that have at least one "$link": "randomtext1" pair under input.
The key word here, both in the question and the following answer, is any:
.[]
| select( any(.input[];
type=="object" and has("$link") and (.["$link"] | index("randomtext1"))))
| .id
Of course if you require the key's value to be "randomtext1", you'd write .["$link"] == "randomtext1".

Searching for object with jQ in command line

I have a JSON file of AWS security groups list. I am trying to fetch the Group Id using the Group Name. The object looks like the following:
{
"SecurityGroups": [{
"IpPermissionsEgress": [
{
"IpProtocol": "-1",
}
],
"Description": "launch-wizard-2 created 2017-10-21T09:19:40.007-04:00",
"GroupName": "MY1SG-PUBLIC-80",
"VpcId": "vpc-ceed12b7",
"OwnerId": "712503525534",
"GroupId": "sg-ee0c979c"
}]
}
With jQ my attempt is as follows:
aws ec2 describe-security-groups | jq '.GroupId' ["GroupName": "MY1SG-PUBLIC-80"]
Error:
jq: error: Could not open file [GroupName:: No such file or directory
jq: error: Could not open file MY1SG-PUBLIC-80]: No such file or directory
Issue 1: Format
https://shapeshed.com/jq-json/
The second input to jq is the file you wish to read from. If this value is - the program will read from the instream.
Issue 2: Selection
https://stedolan.github.io/jq/manual/#select(boolean_expression)
To select an element by value you should/could use a select statement
select(.GroupName == "MY1SG-PUBLIC-80")
jq 'SCOPE | select(.GroupName == "MY1SG-PUBLIC-80") | .GroupId[]' -
where SCOPE is the group you wish to look in. if SCOPE is .[], it will scan every json entry. Following this, it pipes this group into a select filter, and trims it down to only ones that have GroupName set to the given value. This result set is then piped into a key filter, where it only returns the array of matching GroupID's.
I am trying to fetch the Group Id using the Group Name.
Assuming the input has been tweaked to make it valid JSON (*), the filter:
.SecurityGroups[] | select(.GroupName=="MY1SG-PUBLIC-80") | .GroupId
produces:
"sg-ee0c979c"
It might be worthwhile considering this alternative filter:
.[][]|select(.GroupName=="MY1SG-PUBLIC-80")|.GroupId
(*) The input as originally shown has an extraneous comma.