how can i update json array object value - postgresql

I have an array object it is not updated object value.
It always appends a new object in an array.
I have try || operator but it is only working on an object, not array object.
I do the following:
UPDATE "chats" SET
"groupUserStatus"="groupUserStatus" :: JSONB || '{"1":"viewed"}'
WHERE "chats"."chatType"='groupchat' AND
("chats"."groupUserStatus") :: JSONB #> '{"1":"sent"}' :: JSONB
it is updated object successfully but I have update array object.
For Example
Insert Record like this
[{"1":"sent"},{"2":"read"}]
but how i will get record like this (How update record)
[{"1":"viewed"},{"2":"read"}]
sorry for bad english

Use jsonb_set
set groupUserStatus = jsonb_set ( groupUserStatus :: JSONB ,'{0,"1"}', '"viewed"')
DEMO
EDIT : To get the index dynamically and update, you may have to
extract the elements of the array and each key value pairs.
update t t1 set col = jsonb_set ( t2.col :: JSONB ,
('{'||j.idx-1||',"'||e.k||'"}')::text[] , '"viewed"' )
FROM t t2 cross join
jsonb_array_elements (t2.col :: JSONB) with ordinality as j(elem,idx)
cross join jsonb_each_text(j.elem) as e(k,v)
where e.v ='sent'
and t1.id = t2.id
DEMO2

Related

Cast top-level JSONB field as UUID

Consider a table like so:
CREATE TABLE items (
e uuid,
v jsonb
)
I insert the following values:
INSERT INTO items (e, v) VALUES
('9a70439e-33c0-4b34-91f5-efac20b58301', '"92cb730c-8b4f-46ef-9925-4fab953694c6"'),
('92cb730c-8b4f-46ef-9925-4fab953694c6', '"Bob"'),
('92cb730c-8b4f-46ef-9925-4fab953694c6', '52');
Note how for v, I have actually stringified text and numbers -- not an object.
Now, what if I wanted to write a query like so:
WITH match AS (
SELECT * FROM items WHERE e = '9a70439e-33c0-4b34-91f5-efac20b58301'
) SELECT * FROM items JOIN match ON match.v = items.e;
I would get:
Query Error: error: operator does not exist: jsonb = uuid
Is there a way I could tell postgres to "parse" the jsonb value, and see if it is a uuid?
I know about Postgres cast to UUID from JSON , where the ->> operator was able to do the trick. But I can't do that in this case, because our json value is a strong not an object.
You can use ->> 0 to extract the value as text:
SELECT * FROM items
WHERE e = '9a70439e-33c0-4b34-91f5-efac20b58301'
AND e::text = v ->> 0;

How to lower-case all the elements of a JSONB array of strings of each row in a table

I have a table with a field called "data" which is of JSONB type. The content of "data" is an object with one of the fields called "associated_emails", which is an array of strings.
I need to update the existing table so that the content of "associated_emails" is all lower-case. How to achieve that? This is my attempt so far (it triggers error: ERROR: cannot extract elements from a scalar)
update mytable my
set
"data" = safe_jsonb_set(
my."data",
'{associated_emails}',
to_jsonb(
lower(
(
SELECT array_agg(x) FROM jsonb_array_elements_text(
coalesce(
my."data"->'associated_emails',
'{}'::jsonb
)
) t(x)
)::text[]::text
)::text[]
)
)
where
my.mytype = 'something';
You would like to use JSONB_SET and UPDATE the column with something like given below below:
UPDATE jsonb_test
SET data = JSONB_SET(data, '{0,associated_emails}',
JSONB(LOWER(data ->> 'associated_emails'::TEXT)));

Build jsonb array from jsonb field

I have column options with type jsonb , in format {"names": ["name1", "name2"]} which was created with
UPDATE table1 t1 SET options = (SELECT jsonb_build_object('names', names) FROM table2 t2 WHERE t2.id= t1.id)
and where names have type jsonb array.
SELECT jsonb_typeof(names) FROM table2 give array
Now I want to extract value of names as jsonb array. But query
SELECT jsonb_build_array(options->>'names') FROM table
gave me ["[\"name1\", \"name2\"]"], while I expect ["name1", "name2"]
How can I get value in right format?
The ->> operator will return the value of the field (in your case, a JSON array) as a properly escaped text. What you are looking for is the -> operator instead.
However, note that using the jsonb_build_array on that will return an array containing your original array, which is probably not what you want either; simply using options->'names' should get you what you want.
Actually, you don't need to use jsonb_build_array() function.
Use select options -> 'names' from table; This will fix your issue.
jsonb_build_array() is for generating the array from jsonb object. You are following wrong way. That's why you are getting string like this ["[\"name1\", \"name2\"]"].
Try to execute this sample SQL script:
select j->'names'
from (
select '{"names": ["name1", "name2"]}'::JSONB as j
) as a;

Postgres update first record in JSON column for all records

I'm using postgres 9.6.1.
I have an "orders" table that has a column "orderData" that is type JSON.
What each record in the orderData column currently looks like:
[{"orderId":1}, {"orderId":2}, {"orderId":3}]
I'm trying to write a sql query that adds a key to the first order object in each array.
What each record in the orderData column should look like after query:
[{"orderId":1, "isFirstOrder": true}, {"orderId":2}, {"orderId":3}]
NOT WORKING ATTEMPT:
WITH order AS (
SELECT orderData
FROM orders
CROSS APPLY OPENJSON(c) s
WHERE i = 1
)
UPDATE order
SET c = JSON_MODIFY(c, 'isFirstOrder', 'true');
Any help would be greatly appreciated.
demo:db<>fiddle
UPDATE orders
SET c = jsonb_set(c, '{0}', c -> 0 || '{"isFirstOrder": true}');
c -> 0 gets the first element of your array
|| adds the new attribute
jsonb_set rewrites the elements if they exists whereas {0} locates the rewriting position within the array
Postgres JSON functions
For type json there's no function json_set. So you have to do a bit of casting around your json data into jsonb and the final result back into json:
UPDATE orders
SET c = jsonb_set(c::jsonb, '{0}', c::jsonb -> 0 || '{"isFirstOrder": true}')::json
demo:db<>fiddle

How to update a jsonb column in postgresql which is just an array of values and no keys

I need to update a jsonb column which is called "verticals" and the array of values it holds are like HOM, BFB etc. There are no keys in the array.
Table: Product(verticals jsonb, code int)
sample value stored in "verticals" column is
[HOM,rst,NLF,WELSAK,HTL,TRV,EVCU,GRT]
I need to update the value 'HOM' to 'XXX' in the column "verticals" where code =1
My expected output is
[XXX,rst,NLF,WELSAK,HTL,TRV,EVCU,GRT]
Because you chose to store your data in a de-normalized way, updating it is more complicated then it has to be.
You need to first unnest the array (essentially normalizing the data), replace the values, then aggregate them back and update the column:
update product p
set verticals = t.verticals
from (
select jsonb_agg(case when x.v = 'HOM' then 'XXX' else x.v end order by idx) as verticals
from product p2, jsonb_array_elements_text(p2.verticals) with ordinality as x(v,idx)
where code = 1
) t
where p.code = t.code;
This assumes that product.code is a primary (or unique) key!
Online example: http://rextester.com/KZQ65481
If the order of the array elements is not important, this gets easier:
update product
set verticals = (verticals - 'HOM')||'["XXX"]'
where code = 1;
This removes the element 'HOM' from the array (regardless of the posisition) and then appends 'XXX' to the end of the array.
You should use jsonb_set(target jsonb, path text[], new_value jsonb[, create_missing boolean]) and array_position() OR array_replace(anyarray, anyelement, anyelement)
https://www.postgresql.org/docs/9.5/static/functions-json.html
https://www.postgresql.org/docs/10/static/functions-array.html