PostgreSQL Import JSON that structured array -> array? - postgresql

As I googled and some read SO posts like sql - How can I import a JSON file into PostgreSQL? - Stack Overflow, I found a way to parse/import JSON that structured array -> object, such as following(a), using json_populate_recordset, or line by line object, like (b), but I want to import JSON that structured array -> array, like following(c).
(a)
'[
{
"id": 23635,
"name": "Jerry Green",
"comment": "Imported from facebook."
},
{
"id": 23636,
"name": "John Wayne",
"comment": "Imported from facebook."
}
]
(b)
{"id": 23635,"name": "Jerry Green","comment": "Imported from facebook."}
{"id": 23636,"name": "John Wayne","comment": "Imported from facebook."}
(c) ←← wanna parse (actually hundreds of lines not just two)
[
[
1621900800000,
38642.4422973396
],
[
1621932800000,
38192.49969227624
]
]

Here is an idea how you could do this.
insert into my_table (my_bigint_column, my_numeric_column)
select (ja ->> 0)::bigint, (ja ->> 1)::numeric -- mapping expressions here
from jsonb_array_elements
(
$JSONTEXT$
[
[
1621900800000,
38642.4422973396
],
[
1621932800000,
38192.49969227624
]
]
$JSONTEXT$::jsonb) ja;
or, as a parameterized query
insert into my_table (my_bigint_column, my_numeric_column)
select (ja ->> 0)::bigint, (ja ->> 1)::numeric -- mapping expressions here
from jsonb_array_elements (:jsontext::jsonb) ja;
Hundreds of lines would not be an issue.

Related

How to query jarray in jsonb field type?

I have a jsonb field type in a table, it contains the JArray:
[
{
"code": "F01",
"name": "Apple"
},
{
"code": "F02",
"name": "Orange"
},
{
"code": "F03",
"name": "Banana"
}
]
I try to query based on the code and expecting the name like below:
select a.myarray name from fruits a where a.myarray ->> 'code' = 'F02'
but it returns empty
What I missed?
select j ->> 'name'
from jsonb_array_elements(
'[
{"code": "F01","name": "Apple"},
{"code": "F02","name": "Orange"},
{"code": "F03","name": "Banana"}
]'::jsonb) j
where j ->> 'code' = 'F02';
Replace the literal JSON text with the actual value.

PostgresSQL nested jsonb update value of complex key/value pairs

Starting out with JSONB data type and I'm hoping someone can help me out.
I have a table (properties) with two columns (id as primary key and data as jsonb).
The data structure is:
{
"ProductType": "ABC",
"ProductName": "XYZ",
"attributes": [
{
"name": "Color",
"type": "STRING",
"value": "Silver"
},
{
"name": "Case",
"type": "STRING",
"value": "Shells"
},
...
]
}
I would like to update the value of a specific attributes element by name for a row with a given id. For example, for the element with "name"="Case" change the value to "Glass". So it ends up like
{
"ProductType": "ABC",
"ProductName": "XYZ",
"attributes": [
{
"name": "Color",
"type": "STRING",
"value": "Silver"
},
{
"name": "Case",
"type": "STRING",
"value": "Glass"
},
...
]
}
Is this possible with this structure using SQL?
I have created table structure if any of you would like to give it a shot.
dbfiddle
Use the jsonb concatenation operator, ||, to replace keys on the fly:
WITH properties (id, data) AS (
values
(1, '{"ProductType": "ABC","ProductName": "XYZ","attributes": [{"name": "Color","type": "STRING","value": "Silver"},{"name": "Case","type": "STRING","value": "Shells"}]}'::jsonb),
(2, '{"ProductType": "ABC","ProductName": "XYZ","attributes": [{"name": "Color","type": "STRING","value": "Red"},{"name": "Case","type": "STRING","value": "Shells"}]}'::jsonb)
)
SELECT id,
data||
jsonb_build_object(
'attributes',
jsonb_agg(
case
when attribs->>'name' = 'Case' then attribs||'{"value": "Glass"}'::jsonb
else attribs
end
)
) as data
FROM properties m
CROSS JOIN LATERAL JSONB_ARRAY_ELEMENTS(data->'attributes') as a(attribs)
GROUP BY id, data
Updated fiddle

Search inside array of array in JSONB column in Postgresql

I have a JSONB column in my PostgreSQL database. The data looks like this:
{
"cars":
[
{
"id": 1,
"brand": "BMW"
"parts":
[
{
"partId": 5,
"type": "battery"
}
]
},
{
"id": 2,
"brand": "Mercedes"
"parts":
[
{
"partId": 5,
"type": "battery"
},
{
"partId": 6,
"type": "engine"
}
]
}
]
}
Is there any way that I can search for all cars that have a part with type "battery"? How can I search inside of cars array and then inside of the parts array of each car element?
As it's not clear in your question that what output you want. So I am assuming that you want id and brand name in output:
so you try this:
select distinct x.y->>'id', x.y->>'brand'
from test
cross join lateral jsonb_array_elements(data->'cars') x(y)
cross join lateral jsonb_array_elements(x.y->'parts') a(b)
where a.b->>'type'='battery'
DEMO

Get size of an array of strings in PSQL

I'm having some difficulty using the array_length function in psql.
I have a json object that looks like this when a call a function named test_function:
{
"outer": [
{
"keys": {
"id": 5
},
"name": "Joe Bloggs",
"age": "16",
"new_rels": [
"a6h922ao-621y-230p-52bk-t6i84rr3vo6g"
],
"old_rels": [
"9c8b67bf-871e-4004-88be-9a68dae3a86f",
"e6a15929-4aab-4af6-903a-8f8c09bef572"
],
"s_id": 1
}
],
"total": 0,
}
I am trying to get the length of new_rels and old_rels but having some difficulty, possibly due to it being an array of strings.
I have tried this:
select array_length(r->'updates'->0->>'new_rels',1)::bigint from test_function(1) r
But I am getting the following error:
No function matches the given name and argument types. You might need to add explicit type casts
I've even tried simplifying it and doing something like this but it doesn't work with the double quotes - if I change manually to single quotes it does word:
select array_length('["90faa4b9-23fe-4bde-81e7-4326e7356cde", "d642157c-8a55-44de-ac88-ddaa3ab02bb0"]',1);
You want to use the jsonb_array_length() function for jsonb data. The array_length() function is for native arrays such as text[].
with invars as (
select '{
"outer": [
{
"keys": {
"id": 5
},
"name": "Joe Bloggs",
"age": "16",
"new_rels": [
"a6h922ao-621y-230p-52bk-t6i84rr3vo6g"
],
"old_rels": [
"9c8b67bf-871e-4004-88be-9a68dae3a86f",
"e6a15929-4aab-4af6-903a-8f8c09bef572"
],
"s_id": 1
}
],
"total": 0
}'::jsonb as r
)
select jsonb_array_length(r->'outer'->0->'new_rels'),
jsonb_array_length(r->'outer'->0->'old_rels')
from invars;
jsonb_array_length | jsonb_array_length
--------------------+--------------------
1 | 2
(1 row)
Also, you had an extra comma after the total key.

Extracting info out of lists inside a jsonb

I have a with a jsonb column called jsonb that contains data in the following format.
{
"stuff": [
{
"name": "foo",
"percent": "90.0000"
},
{
"name": "bar",
"percent": "10.0000"
}
],
"countries": [
{
"name": "USA",
"value": "30"
},
{
"name": "Canada",
"value": "25"
},
{
"name": "Mexico",
"value": "20"
},
{
"name": "Ecuador",
"value": "10"
}
]
}
I am having a lot of trouble working with this data. Specifically what I want to do is find all the different values "name" can have in "stuff" as well as in "countries", kind of like a SELECT distinct.
But my problem is that I can't seem to extract anything useful from this jsonb. My approach so far was to do
SELECT jsonb->>'stuff' FROM table, but this only gave me a column of type text which contained [{"name": "foo","percent": "90.0000"},{"name": "bar","percent": "10.0000"}].
But since this is text I can't really do anything with it. I also tried SELECT jsonb_array_elements_text(jsonb) FROM table but that returned the following Error:
ERROR: cannot extract elements from an object
SQL state: 22023
Any help with working with this format of data is greatly appreciated!
You need to unnest each array separately and then create a union on the result of those two steps:
select c.x ->> 'name'
from the_table
cross join lateral jsonb_array_elements(json_column -> 'countries') as c(x)
union
select s.x ->> 'name'
from the_table
cross join lateral jsonb_array_elements(json_column -> 'stuff') as s(x);
Online example: https://rextester.com/ZEOIXF91294