how to query for values in a deep nested json array in Postresql? - sql

I have a column of json objects (jsonb type) in Posgresql in this format:
[ {"qos1": [ {
"country_id" : [{"id":"IT",...}, {"id":"FR",...},...]
},...],...}
...]
So I am dealing with deep nested arrays of jsons.
I need to retrieve the row containing qos1 -> country_id -> id:"FR"
How to do this?
I tried different combinations such as:
SELECT *
FROM mytable
WHERE datacolumn -> 'qos1' -> 'country_id' -> 'id' = '"FR"'
with no luck.

You can use a JSON path expression:
select *
from the_table
where datacolumn ## '$.qos1[*].country_id[*].id == "FR"'

Related

Is it possible to add index values to the rows of a postgreSQL query when expanding JSON array with json_array_elements?

I have a database of resume data in json format which I am trying to transform.
One of the sections in each jsib is work_history, this is in the form of a json array i.e.
"work_experience":[
{
"job_title":"title",
"job_description":"description"
},
{
"job_title":"title",
"job_description":"description"
}
]
I am iterating over each resume (json file) and importing this data into a new table using dbt and postgreSQL with each element of the array being a new row with the associated metadata of the resume. Here is the code I used for this
select
json_array_elements(rjt.raw_json::json -> 'data' -> 'work_experience') as we,
json_array_elements(rjt.raw_json::json -> 'data' -> 'work_experience') -> 'job_title' as "name",
rjt.uuid as uuid
from raw_json_table rjt
The last thing that I need to do is add a column that lists the index that each job came from within its individual workexperience array i.e. if a job was the third element in the array it would have a 2 in the "source_location" column. How can I generate this index such that it starts at 0 for each new json file.
Move the function to the FROM clause (where set-returning functions should be used). Then you can use with ordinality which also returns a column that indicates the index inside the array
select w.experience as we,
w.experience ->> 'job_title' as "name",
w.experience ->> 'job_description' as "description",
w.idx as "index",
rjt.uuid as uuid
from raw_json_table rjt
left join json_array_elements(rjt.raw_json::json -> 'data' -> 'work_experience') with ordinality
as w(experience, idx) on true
The left join is necessary so that rows from raw_json_table that don't contain array elements are still included.

How to select single field from array of json objects?

I have a JSONB column with values in following JSON structure
{
"a": "value1", "b": [{"b1": "value2", "b3": "value4"}, {"b1": "value5", "b3": "value6"}]
}
I need to select only b1 field in the result. So expected result would be
["value2", "value5"]
I can select complete array using query
select columnname->>'b' from tablename
step-by-step demo:db<>fiddle
SELECT
jsonb_agg(elements -> 'b1') -- 2
FROM mytable,
jsonb_array_elements(mydata -> 'b') as elements -- 1
a) get the JSON array from the b element (b) extract the array elements into one row each
a) get the b1 values from the array elements (b) reaggregate these values into a new JSON array
If you are using Postgres 12 or later, you an use a JSON path query:
select jsonb_path_query_array(the_column, '$.b[*].b1')
from the_table;

Get a list of all objects with the same key inside a jsonb array

I have a table mytable and a JSONB column employees that contains data like this:
[ {
"name":"Raj",
"email":"raj#gmail.com",
"age":32
},
{
"name":"Mohan",
"email":"Mohan#yahoo.com",
"age":21
}
]
I would like to extract only the names and save them in a list format, so the resulting cell would look like this:
['Raj','Mohan']
I have tried
select l1.obj ->> 'name' names
from mytable t
cross join jsonb_array_elements(t.employees) as l1(obj)
but this only returns the name of the first array element.
How do I get the name of all array elements?
Thanks!
PostgreSQL 11.8
In Postgres 12, you can use jsonb_path_query_array():
select jsonb_path_query_array(employees, '$[*].name') as names
from mytable
In earlier versions you need to unnest then aggregate back:
select (select jsonb_agg(e -> 'name')
from jsonb_array_elements(employees) as t(e)) as names
from mytable

Get element from array of JSON postgres

I have a column x with data type jsonb
and the value looks like:
[
[{"string":"whateverstring1"}],
[{"string":"whateverstring2"}]
]
How to return each element of the array?
Something like this:
"whateverstring1","whateverstring2"
demo:db<>fiddle
SELECT jsonb_array_elements(jsonb) -> 0 -> 'string'
FROM (
SELECT '[[{"string":"whateverstring1"}],[{"string":"whateverstring2"}]]'::jsonb
) s
jsonb_array_elements extract each element into one row
-> 0 gives the first element of the nested arrays which is {"string":"whateverstring1"}
-> 'string' gives the value of the elements

Postgres: Loop through json array equivalent in SQL?

I am using postgres 9.6.3 and need to convert the following python code to a sql query:
data = response.json()
activities = data['Response']['data']['activities']
for activity in activities:
activityHash = int(activity['activityHash'])
if activityHash == 2659248071:
clears = int(activity['values']['activityCompletions']['basic']['value'])
The table has two columns: (membershipid integer primary key, data jsonb). I am not sure how to handle an array like this in sql. The array is variable length and might or might not include an entry where activityHash == the desired value.
The desired result from the query would be something like SELECT membershipid, clears FROM table.
I was looking for jsonb_array_elements(activities)
I recommend you check out this link that walks you through how to traverse JSONB in Postgres.
Try the following query and see if that works for you:
SELECT
membershipid,
'data' -> 'activity' -> 'response' -> 'data' -> 'activities' ->> 'activityHash' AS activityHash,
'data' -> 'activity' -> 'response' -> 'data' -> 'activities' -> 'activityHash' -> 'values' -> 'activityCompletions' -> 'basic' ->> 'value' AS clears
FROM yourtablename
WHERE
('data' -> 'activity' -> 'response' -> 'data' -> 'activities' ->> 'activityHash')::int = 2659248071;