How to update a json array using the key - sql

Let's say I have this json in my jsonb column
{
"fields": [
{
"name": "firstName",
"age": 17
},
{
"name": "lastName",
"age": 25
},
...
}
How can I update the "firstName" only without using the index?
I have this so far, but this is using the index which I don't want to use
UPDATE person
SET
field = jsonb_set(field,
concat('{fields, 0, name'}')::text[],
'new value'::jsonb,
TRUE)

You will need to unnest the array elements, replace the one you want and then aggregate them back:
update the_table tg
set data = data||(select jsonb_build_object(
'fields', jsonb_agg(case
when t.j ->> 'name' = 'firstName'
then t.j||'{"name": "new_name"}'
else t.j
end))
from jsonb_array_elements(tg.data -> 'fields') as t(j))
where ....;
Online example: https://rextester.com/BZVKD68215

Related

Filtering jsonb array in postgreSql

I have a table with a jsonb field of the following type:
[
{
"Id": "98f2a810-8f29-4707-9098-759eec83b2d5",
"Data": {
"value": 6
},
"Created": "2022-12-15T10:04:04.8100461Z"
},
{
"Id": "950df931-abfd-460f-916f-14b00d3e1593",
"Data": {
"value": "hello world"
},
"Created": "2022-12-15T10:04:04.9270694Z"
}
]
Now I can filter records only by decomposing the jsonb array into separate lines and join them:
LEFT JOIN LATERAL jsonb_array_elements(""attributes"") as x(attribute) ON TRUE
and filter:
WHERE x.attribute ->> 'Id' ILIKE '98f2a810-8f29-4707-9098-759eec83b2d5' and cast(x.attribute -> 'Data' ->> 'value' as numeric) = 6
But if I need filter by two attributes with AND operator it doesn't work(the results exclude each other).
How I can filter jsonb array without separate and join elements?

Postgreql json data how to list all elements of an array

I have a jsonB field in postgresql DB table, it has data like this
{
"units": [
{
"id": 299872379221376,
"unitNumber": "1",
"unitFloorSpace": 1,
"createdTimeStamp": 1587994498586
},
{
"id": 299872417011074,
"unitNumber": "2",
"unitFloorSpace": 2,
"createdTimeStamp": 1588001330085
}
]
}
I just want to list all unitNumbers like below, what would be the query for that?
1,
2,
I have tried below json query but that doesn’t list
Select form_data -> units -> unitNumbers from table where row_id =1;
here is one way:
select jsonb_array_elements(jsonb_extract_path(jdata,'units')) ->> 'unitNumber' as UnitNumber
from tableName;
db<>fiddle here

Querying nested Json object in postgres

I have a jsonb column in my table and data is in this format:
[
{
"id": 1,
"DATA": {
"a": "XXX",
"key": "value1"
}
},
{
"id": 2,
"DATA": {
"a": "XXX",
"key": "value2"
}
}
]
I would like to get the count of rows in which key = value1. I tried some queries like:
select count(t.id)
from my_table t,
jsonb_array_elements(summary->'DATA') elem
where elem->>'key' = 'value1';
It returned 0 rows, though there are rows in db with that key value pair. Thanks in advance,
Use jsonb_array_elements() for the column summary as it is in the form of json array.
select count(distinct t.id)
from my_table t
cross join jsonb_array_elements(summary) elem
where elem->'DATA'->>'key' = 'value1';
Alternatively, you can get rid of the function using #> operator:
select count(t.id)
from my_table t
where summary #> '[{"DATA":{"key":"value1"}}]'
The second solution should be faster.
Db<>fiddle.

Remove json object from array of jsons in postgres

I have the following json in my column in posgres database.
Column items in table products
{
"name": "Super name",
"type": "Green",
"information": [
{
"name": "first",
"value": "high"
},
{
"name": "second",
"value": "medium"
}
],
}
I want to delete json object using jsonb
{
"name": "second",
"value": "medium"
}
I try this:
update products set items = jsonb_set(items, '{information}', (items->'information') - '{"name": "second", "value": "medium"}');
I tried different approaches but nothing work correctly.
The "minus" operator doesn't work on objects, only keys. And it doesn't work on arrays of objects either.
I would write a function that removes a single object from an array.
create function remove_element(p_input jsonb, p_to_remove jsonb)
returns jsonb
as
$$
select coalesce(jsonb_agg(t.item order by t.idx), '[]')
from jsonb_array_elements(p_input) with ordinality as t(item, idx)
where t.item <> p_to_remove;
$$
language sql
immutable;
Then you can use it like this:
update products
set items = jsonb_set(items, '{information}', remove_element(items -> 'information', '{"name": "second", "value": "medium"}'))
where ...
Online example

Trying to construct PostgreSQL Query to extract from JSON a text value in an object, in an array, in an object, in an array, in an object

I am constructing an interface between a PostgreSQL system and a SQL Server system and am attempting to "flatten" the structure of the JSON data to facilitate this. I'm very experienced in SQL Server but I'm new to both PostgreSQL and JSON.
The JSON contains essentially two types of structure: those of type "text" or "textarea" where the value I want is in an object named value (the first two cases below) and those of type "select" where the value object points to an id object in a lower-level options array (the third case below).
{
"baseGroupId": {
"fields": [
{
"id": "1f53",
"name": "Location",
"type": "text",
"options": [],
"value": "Over the rainbow"
},
{
"id": "b547",
"name": "Description",
"type": "textarea",
"options": [],
"value": "A place of wonderful discovery"
},
{
"id": "c12f",
"name": "Assessment",
"type": "select",
"options": [
{
"id": "e5fd",
"name": "0"
},
{
"id": "e970",
"name": "1"
},
{
"id": "0ff4",
"name": "2"
},
{
"id": "2db3",
"name": "3"
},
{
"id": "241f",
"name": "4"
},
{
"id": "3f52",
"name": "5"
}
],
"value": "241f"
}
]
}
}
Those with a sharp eye will see that the value of the last value object "241f" can also be seen within the options array against one of the id objects. When nested like this I need to extract the value of the corresponding name, in this case "4".
The JSON-formatted information is in table customfield field textvalue. It's datatype is text but I'm coercing it to json. I was originally getting array set errors when trying to apply the criteria in a WHERE clause and then I read about using a LATERAL subquery instead. It now runs but returns all the options, not just the one matching the value.
I'm afraid I couldn't get an SQL Fiddle working to reproduce my results, but I would really appreciate an examination of my query to see if the problem can be spotted.
with cte_custombundledfields as
(
select
textvalue
, cfname
, json_array_elements(textvalue::json -> 'baseGroupId'->'fields') ->> 'name' as name
, json_array_elements(textvalue::json -> 'baseGroupId'->'fields') ->> 'value' as value
, json_array_elements(textvalue::json -> 'baseGroupId'->'fields') ->> 'type' as type
from
customfield
)
, cte_custombundledfieldsoptions as
(
select *
, json_array_elements(json_array_elements(textvalue::json -> 'baseGroupId'->'fields') -> 'options') ->> 'name' as value2
from
cte_custombundledfields x
, LATERAL json_array_elements(x.textvalue::json -> 'baseGroupId'->'fields') y
, LATERAL json_array_elements(y -> 'options') z
where
type = 'select'
and z ->> 'id' = x.value
)
select *
from
cte_custombundledfieldsoptions
I posted a much-simplified rewrite of this question which was answered by Bergi.
How do I query a string from JSON based on another string within the JSON in PostgreSQL?