Flatten JSON data file - json

I'm a JQ newb, and have been wrestling with this task for while.
Our source JSON file looks like this...
[
{
"id": "xxxx",
"title": "xxxx",
"created_at": "xxxx",
"updated_at": "xxxx",
"fields": [
{
"usernamevalue": "xxxx",
"reference": "xxxx"
},
{
"passwordvalue": "xxxx",
"reference": "xxxx"
},
{
"otherlabel": "xxxx",
"otherreference": "xxxx"
}
]
},
{
"id": "xxxx",
"title": "xxxx",
"created_at": "xxxx",
"updated_at": "xxxx",
"fields": [
{
"usernamevalue": "xxxx",
"reference": "xxxx"
},
{
"passwordvalue": "xxxx",
"reference": "xxxx"
},
{
"otherlabel": "xxxx",
"otherreference": "xxxx"
}
]
}
]
We are trying to end up with...
[
{
"title": "xxxx",
"updated_at": "xxxx",
"usernamevalue": "xxxx",
"passwordvalue": "xxxx"
},
{
"title": "xxxx",
"updated_at": "xxxx",
"usernamevalue": "xxxx",
"passwordvalue": "xxxx"
}
]
As such, the goals are...
End up with one, "flat" item for each entry -- so that we can then convert it to a CSV.
Only get the "title" and "updated_at" fields from the top level.
Only get fields with keys = "usernamevalue" and "passwordvalue" from the subordinate "fields" array, and move those fields to the top level.
Any guidance would be GREATLY appreciated!
(I've already spent more hours on this than I care to admit.)
THANK YOU

If usernamevalue and passwordvalue have only one occurrence as in your sample file, you can add the fields object, and then extract from it as you would with the outside keys:
jq 'map({id, updated_at} + (.fields | add | {usernamevalue, passwordvalue}))'
[
{
"id": "xxxx",
"updated_at": "xxxx",
"usernamevalue": "xxxx",
"passwordvalue": "xxxx"
},
{
"id": "xxxx",
"updated_at": "xxxx",
"usernamevalue": "xxxx",
"passwordvalue": "xxxx"
}
]
Demo
If your ultimate goal is a CSV output of the values, you'd rather go for an array than an object, which could be something like:
jq -r '.[] | [.id, .updated_at, (.fields | add | .usernamevalue, .passwordvalue)] | #csv'
"xxxx","xxxx","xxxx","xxxx"
"xxxx","xxxx","xxxx","xxxx"
Demo

You could parse the JSON object through their keys.
var jsonObject = [
{
"foo": "bar",
"foo1": "bar1",
"field": [
{
"username": "john#gm.com",
"context": "foob"
},
{
"password": "kek",
"context": "bar1"
},
{
"other": "foobar",
"context": "foobarbar"
}
]
}
]
for (var i = 0; i < jsonObject.field.length; i++)
{
for(var key in jsonObject.field[i])
{
if(key == "username")
{
jsonObject.usernamevalue = jsonObject.field[i].username;
} else if(key == "password")
{
jsonObject.passwordvalue = jsonObjecct.field[i].password;
}
}
}
//Afterwards, you can delete the field
delete jsonObject.field;

Related

How to extract a paticular key from the json

I am trying to extract values from a json that I obtained using the curl command for api testing. My json looks as below. I need some help extracting the value "20456" from here?
{
"meta": {
"status": "OK",
"timestamp": "2022-09-16T14:45:55.076+0000"
},
"links": {},
"data": {
"id": 24843,
"username": "abcd",
"firstName": "abc",
"lastName": "xyz",
"email": "abc#abc.com",
"phone": "",
"title": "",
"location": "",
"licenseType": "FLOATING",
"active": true,
"uid": "u24843",
"type": "users"
}
}
{
"meta": {
"status": "OK",
"timestamp": "2022-09-16T14:45:55.282+0000",
"pageInfo": {
"startIndex": 0,
"resultCount": 1,
"totalResults": 1
}
},
"links": {
"data.createdBy": {
"type": "users",
"href": "https://abc#abc.com/rest/v1/users/{data.createdBy}"
},
"data.fields.user1": {
"type": "users",
"href": "https://abc#abc.com/rest/v1/users/{data.fields.user1}"
},
"data.modifiedBy": {
"type": "users",
"href": "https://abc#abc.com/rest/v1/users/{data.modifiedBy}"
},
"data.fields.projectManager": {
"type": "users",
"href": "https://abc#abc.com/rest/v1/users/{data.fields.projectManager}"
},
"data.parent": {
"type": "projects",
"href": "https://abc#abc.com/rest/v1/projects/{data.parent}"
}
},
"data": [
{
"id": 20456,
"projectKey": "Stratus",
"parent": 20303,
"isFolder": false,
"createdDate": "2018-03-12T23:46:59.000+0000",
"modifiedDate": "2020-04-28T22:14:35.000+0000",
"createdBy": 18994,
"modifiedBy": 18865,
"fields": {
"projectManager": 18373,
"user1": 18628,
"projectKey": "Stratus",
"text1": "",
"name": "Stratus",
"description": "",
"date2": "2019-03-12",
"date1": "2018-03-12"
},
"type": "projects"
}
]
}
I have tried the following, but end up getting error:
▶ cat jqTrial.txt | jq '.data[].id'
jq: error (at <stdin>:21): Cannot index number with string "id"
20456
Also tried this but I get strings outside the object that I am not sure how to remove:
cat jqTrial.txt | jq '.data[]'
Assuming you want the project id not the user id:
jq '
.data
| if type == "object" then . else .[] end
| select(.type == "projects")
| .id
' file.json
There's probably a better way to write the 2nd expression
Indeed, thanks to #pmf
.data | objects // arrays[] | select(.type == "projects").id
Your input consists of two JSON documents; both have a data field on top level. But while the first one is itself an object which has an .id field, the second one is an array with one object item, which also has an .id field.
To retrieve both, you could use the --slurp (or -s) option which wraps both top-level objects into an array, then you can address them separately by index:
jq --slurp '.[0].data.id, .[1].data[].id' jqTrial.txt
24843
20456
Demo

add a parameter name to a json file with jq

I am trying to make my json file that looks like this
{
"database_details": {
"age": "false",
"help": "xxxx",
"host": "",
"servername": "fra02",
"db_name": "config_tools",
"pass": "xxxx",
"user": "default",
},
{
"age": "false",
"help": "xxxx",
"host": "",
"servername": "fra03",
"db_name": "config_tools",
"pass": "xxxx",
"user": "default",
}
}
to look like
{
"database_details": {
"fra02":{
"age": "false",
"help": "xxxx",
"host": "",
"servername": "fra02",
"db_name": "config_tools",
"pass": "xxxx",
"user": "default",
},
"fra03": {
"age": "false",
"help": "xxxx",
"host": "",
"servername": "fra02",
"db_name": "config_tools",
"pass": "xxxx",
"user": "default",
}
}
}
I have tried jq but not sure if that is the right approach?
I have thought about using awk or sed but not sure that is the cleanest route?
Assuming valid JSON like
{
"database_details": [
{
"age": "false",
"help": "xxxx",
"host": "",
"servername": "fra02",
"db_name": "config_tools",
"pass": "xxxx",
"user": "default"
},
{
"age": "false",
"help": "xxxx",
"host": "",
"servername": "fra03",
"db_name": "config_tools",
"pass": "xxxx",
"user": "default"
}
]
}
you can use the filter
.database_details |= (map({key: .servername, value: .}) | from_entries)
The array associated with database_details is turned into an array of key/value pairs, which from_entries turns into a new object that |= assigns back to the key database_details in the original object.

How to retrieve deep-linked kv pair using jq

got to this section of json with jq -r '.update[]' now need to find, operation:restrictions:user:results:username,userKey
"update": {
"operation": "update",
"restrictions": {
"user": {
"results": [
{
"type": "known",
"username": "xxxx",
"userKey": "yyyyy",
"profilePicture": {
"path": "/download/attachments/49710215/user-avatar",
"width": 48,
"height": 48,
"isDefault": false
},
"displayName": "xxxyyyzzz",
"_links": {
"self": "aa"
},
"_expandable": {
"status": ""
}
},
Assuming the input as shown has been tidied a bit to make it valid JSON, running
jq -r '
.update
| [.operation] + (.restrictions.user.results[] | [.username, .userKey])
| #csv
'
against it would yield:
"update","xxxx","yyyyy"

Looping and searching through JSON using PowerShell

I have a JSON file that has following contents:
{
"status": "UP",
"details": {
"graphDBCheck": {
"status": "UP"
},
"ds": {
"status": "UP",
"details": {
"total": 100,
"free": 50,
"threshold": 30
}
},
"db": {
"status": "UP",
"details": {
"ADS": {
"status": "UP",
"details": {
"database": "Influx",
"hello": "Hello"
}
},
"EARDS": {
"status": "UP",
"details": {
"database": "Oracle",
"hello": "Hello"
}
},
"EFRDS": {
"status": "UP",
"details": {
"database": "Sybase",
"hello": "Hello"
}
}
}
}
}
}
I need to be able to transform this into a CSV file that has each element's name as header and it's status or value as the next row. First "status" would have column name "API_Status"
For instance:
API_Status,graphDBCheck,ds,db,ADS,EARDS,EFRDS
UP,UP,UP,UP,UP,UP,UP
Challenge here is to make this dynamic so the output will always include any other element added that has "status" in it.
I tried this and it works but I need a dynamic way do to this:
$x = Invoke-RestMethod $url -Verbose:$VerbosePreference
[pscustomobject][ordered]#{
'API_Status' = $x.status
'db' = $x.details.db.status
'ds' = $x.details.diskspace.status
'ds_Total' = $x.details.ds.details.total
'ds_Free' = $x.details.ds.details.free
'graphDBCheck' = $x.details.graphDBCheck.status
'ADS' = $x.details.db.details.auroraDataSource.status
'EARDS' = $x.details.db.details.EARDS.status
'EFRDS' = $x.details.db.details.edsFirstRowsDataSource.status
}
In an ideal world, the json would be structured like this, as an expandable array with uniform properties.
[
{
"name": "API_Status",
"status": "UP"
},
{
"name": "graphDBCheck",
"status": "UP"
},
{
"name": "ds",
"status": "UP"
},
{
"name": "db",
"status": "UP"
},
{
"name": "ADS",
"status": "UP"
},
{
"name": "EARDS",
"status": "UP"
},
{
"name": "EFRDS",
"status": "UP"
}
]
Or as a csv:
name,status
API_Status,UP
graphDBCheck,UP
ds,UP
db,UP
ADS,UP
EARDS,UP
EFRDS,UP
There's plenty of other posts about looping through powershell properties Iterate over PSObject properties in PowerShell or looping through json properties: Iterating through a JSON file PowerShell

Using jq to return specific information in JSON object

I wish to parse individual elements of inner JSON object to build / load in the database.
The following is the JSON object. How can I parse elements like id, name queue etc? I will iterate it in loop and work and build the insert query.
{
"apps": {
"app": [
{
"id": "application_1540378900448_18838",
"user": "hive",
"name": "insert overwrite tabl...summary_view_stg_etl(Stage-2)",
"queue": "Data_Ingestion",
"state": "FINISHED",
"finalStatus": "SUCCEEDED",
"progress": 100
},
{
"id": "application_1540378900448_18833",
"user": "hive",
"name": "insert into SNOW_WORK...metric_definitions')(Stage-13)",
"queue": "Data_Ingestion",
"state": "FINISHED",
"finalStatus": "SUCCEEDED",
"progress": 100
}
]
}
}
You're better off converting the data to a format easily consumed by a database processor, like csv, then do something about it.
$ jq -r '(.apps.app[0] | keys_unsorted) as $k
| $k, (.apps.app[] | [.[$k[]]])
| #csv
' input.json
its pretty simple just fetch elment which is having an array of values.
var JSONOBJ={
"apps": {
"app": [
{
"id": "application_1540378900448_18838",
"user": "hive",
"name": "insert overwrite tabl...summary_view_stg_etl(Stage-2)",
"queue": "Data_Ingestion",
"state": "FINISHED",
"finalStatus": "SUCCEEDED",
"progress": 100
},
{
"id": "application_1540378900448_18833",
"user": "hive",
"name": "insert into SNOW_WORK...metric_definitions')(Stage-13)",
"queue": "Data_Ingestion",
"state": "FINISHED",
"finalStatus": "SUCCEEDED",
"progress": 100
}
]
}
}
JSONOBJ.apps.app.forEach(function(o){console.log(o.id);console.log(o.user);console.log(o.name);})