Cast uuid into a jsonb field - postgresql

Consider the following tables:
CREATE TABLE uuid_items (
u uuid
);
CREATE TABLE jsonb_items (
j jsonb
);
INSERT INTO uuid_items (u) values ('6de8874f-99f0-4b05-8c83-b904b3065ff0');
INSERT INTO jsonb_items (j) values ('"6de8874f-99f0-4b05-8c83-b904b3065ff0"');
Now, I would like to join uuid_items on jsonb_items. Something like so:
SELECT * from uuid_items JOIN jsonb_items ON uuid_items.u::jsonb = jsonb_items.j;
This will give me the error:
Query Error: error: cannot cast type uuid to jsonb
I thought of using something like jsonb_build_array as a hack:
SELECT * from uuid_items JOIN jsonb_items ON jsonb_build_array(uuid_items.u)->0 = jsonb_items.j;
But I wonder: is there a better way? How could I cast uuid_items.u, into a valid jsonb value?
You can play with the playground here

You can either convert both to text:
WHERE u::text = j ->> 0
or convert both to jsonb:
WHERE to_jsonb(u) = j
or convert both to uuid:
WHERE u = (j ->> 0)::uuid
Choose according to the indexes you have in place. Best practice is to use the proper data type (uuid) for both columns.

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;

Fetch rows from postgres table which contains a specific id in jsonb[] column

I have a details table with adeet column defined as jsonb[]
a sample value stored in adeet column is as below image
Sample data stored in DB :
I want to return the rows which satisfies id=26088 i.e row 1 and 3
I have tried array operations and json operations but it does'nt work as required. Any pointers
Obviously the type of the column adeet is not of type JSON/JSONB, but maybe VARCHAR and we should fix the format so as to convert into a JSONB type. I used replace() and r/ltrim() funcitons for this conversion, and preferred to derive an array in order to use jsonb_array_elements() function :
WITH t(jobid,adeet) AS
(
SELECT jobid, replace(replace(replace(adeet,'\',''),'"{','{'),'}"','}')
FROM tab
), t2 AS
(
SELECT jobid, ('['||rtrim(ltrim(adeet,'{'), '}')||']')::jsonb as adeet
FROM t
)
SELECT t.*
FROM t2 t
CROSS JOIN jsonb_array_elements(adeet) j
WHERE (j.value ->> 'id')::int = 26088
Demo
You want to combine JSONB's <# operator with the generic-array ANY construct.
select * from foobar where '{"id":26088}' <# ANY (adeet);

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 match data in string array

I have a postgres table where the column type is text but it has data which looks like in an array:
["97aa63c0-c562-11e3-b216-000180810a27","33fff220-b6be-11e3-be89-000180810a27"]
My first question is what is this data structure?
How can I match in a query: For Example:
If the table name id X and column name where data exist is products
Select * from X where product='97aa63c0-c562-11e3-b216-000180810a27'
How can I do something like that?
That looks like a json or python array literal containing uuid values.
There are many reasons not to store data like this but it sounds like you didn't design the DB.
In modern PostgreSQL I'd parse it as json. In older versions I'd use string functions to convert it. In 9.4 this will work:
WITH arr(uuids) AS (
VALUES('["97aa63c0-c562-11e3-b216-000180810a27","33fff220-b6be-11e3-be89-000180810a27"]')
)
SELECT
elem::uuid
FROM arr, json_array_elements_text(
uuids::json
) elem;
but 9.3 doesn't have json_array_elements_text so you have to write:
WITH arr(uuids) AS (VALUES('["97aa63c0-c562-11e3-b216-000180810a27","33fff220-b6be-11e3-be89-000180810a27"]'))
SELECT json_array_element(uuids::json, ss-1) FROM arr, generate_series( 1, json_array_length(uuids::json) ) ss;
and in still older versions:
WITH arr(uuids) AS (VALUES('["97aa63c0-c562-11e3-b216-000180810a27","33fff220-b6be-11e3-be89-000180810a27"]'))
SELECT left(right(elem,-1),-1)::uuid FROM arr, unnest(string_to_array(left(right(uuids, -1),-1), ',')) elem;