Converting varchar array to array with jsonb objects - postgresql

I have an array of strings, like this:
SELECT ARRAY['user1#example.com', 'user2#example.com', 'user3#example.com'];
How do I convert (map?) it into a jsonb array of jsonb objects like this?:
SELECT [{"email": "user1#example.com"}, {"email": "user2#example.com"}, {"email": "user3#example.com"}]::jsonb;

demo:db<>fiddle
SELECT
jsonb_agg(jsonb_build_object('email', elems))
FROM (
SELECT ARRAY['user1#example.com', 'user2#example.com', 'user3#example.com'] AS a
) s,
unnest(a) AS elems
Expand the array elements into one record each with unnest()
Create the JSON objects using jsonb_object_build() to create the key/value structure your are expecting
re-aggregate these objects into one new JSON array using jsonb_agg()

Related

Casting an array of strings to an array of integers

How can I cast an array of string into an array of integers?
Below is my array
["6", "5"]
I want convert into int array
[6, 5]
demo:db<>fiddle
SELECT
array_agg(elems::int)
FROM unnest(ARRAY['5', '6']) as elems
Expand the array into one record per element
Reaggregate cast integer values
To ensure the original order, you need to add WITH ORDINALITY, which adds an index to the original array:
SELECT
array_agg(elems.value::int ORDER BY elems.index)
FROM unnest(ARRAY['5', '6']) WITH ORDINALITY as elems(value, index)
If you have a JSON array instead, the algorithm is the same, only the used functions have different names:
SELECT
json_agg(elems.value::int ORDER BY elems.index)
FROM json_array_elements_text('["5", "6"]'::json) WITH ORDINALITY as elems(value, index)
EDIT: According to comment:
this is my query. SELECT data->>'pid' FROM user_data where
data->>'pid' is not null How can I update pid to array of integers ?
demo:db<>fiddle
You have to expand and reaggregate nonetheless:
SELECT
json_agg(elems::int) -- 2
FROM user_data,
json_array_elements_text(data -> 'pid') as elems -- 1
WHERE data->>'pid' IS NOT NULL
GROUP BY id
You can’t “cast”, but you can get something very close to a cast:
array(select unnest(myArray)::int)
As a testable query:
select array(select unnest(array['5', '6'])::int)
See live demo.
When applying to a column of a selected table:
select
array(select unnest(myArrayCol)::int)
from myTable
See live demo.
This syntax preserves order.

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;

get first element from jsonb list of strings postgres

I have a List which is stored in my table as a jsonb and need a native query to get the first element from this jsonb column
Tried using jsonb_array_elements_text but couldn't get it to work.
select col from tbl;
returns:
["abc", "def", "etc"]
I need a query which can just return me abc
You can use the operator that picks the n-th element of an array:
select col ->> 0 as first_element
from tbl;
Note that unlike Postgres native arrays, the first element in a JSON array has the index 0

Postgresql query json element inside json array

I have a table like:
CREATE TABLE stats
(
item character varying,
data jsonb
);
it contains values like
ITEM DATA
test1 [{"id":"1", "country":"UK"},{"id":"2", "country":"INDIA"}]
test2 [{"id":"1", "country":"US"},{"id":"4", "country":"CHINA"},{"id":"5", "country":"CHINA"}]
I need to get number of distinct json objects where country is 'CHINA' and item is '%test%';
In this case the output should be 2, ie, [{"id":"4", "country":"CHINA"},{"id":"5", "country":"CHINA"}]
I am using the following query
SELECT * FROM stats t
WHERE ( data #> '[{"country":"CHINA"}]')
and t.item ilike '%test%';
output : [{"id":"1", "country":"US"},{"id":"4", "country":"CHINA"},{"id":"5", "country":"CHINA"}]
What should i do so that i get the array of objects which has 'CHINA' as countries?
Use jsonb_array_elements() to get single json objects, filter them and use jsonb_agg() to aggregate into a json array.
select item, jsonb_agg(obj)
from stats, jsonb_array_elements(data) obj
where obj->>'country' = 'CHINA'
group by 1;

How to create and store array of objects in postgresql

In postgresql allowed array types or integer and text.But i need to create array of objects.how can i do that.
myarray text[]; //for text ['a','b','c']
myarray integer[]; //for integer[1,2,3]
I need to create the array like below
[{'dsad':1},{'sdsad':34.6},{'sdsad':23}]
I dont want to use JSON type.Using array type i need to store the array of objects.
If you're running Postgres 9.2+, you can use the JSON type.
For example, we could do
create table jsontest (id serial primary key, data json);
insert into jsontest (data) values ('[{"dsad":1},{"sdsad":34.6},{"sdsad":23}]');
And query the data with
select data->1 from jsontest;
{"sdsad":34.6}
You say:
I dont want to use JSON type
but you cannot use an ordinary array, as PostgreSQL arrays must be of homogenous types. You can't have a 2-dimensional array of text and integer.
What you could do if you don't want to use json is to create a composite type:
CREATE TYPE my_pair AS (blah text, blah2 integer);
SELECT ARRAY[ ROW('dasd',2), ROW('sdsad', 34.6), ROW('sdsad', 23) ]::my_pair[]
which will emit:
array
----------------------------------------
{"(dasd,2)","(sdsad,35)","(sdsad,23)"}
(1 row)
If you don't want that, then json is probably your best bet. Or hstore:
SELECT hstore(ARRAY['a','b','c'], ARRAY[1,2,3]::text[])
hstore
------------------------------
"a"=>"1", "b"=>"2", "c"=>"3"
(1 row)
JSON is your preferred answer, but more info as to why.
You can do something like:
SELECT array_agg(v)
FROM mytable v;
However you get something that looks like this:
{"(dsad,1)","(sdsad,34.6)","(""sdsad,var"",23)"}
It is then up to you to know how to decode this (i.e. column order). This is possible to do programmatically but is much easier with JSON.
It's hacky, but what about using an array for each property in the object (and its corresponding scalar type). If you have a data model layer in your get/read you could put the arrays "back together" into an array of objects and in your save method you would break you objects apart into synchronized arrays. This might be complicated by your example of each object not having the same properties; IDK how you'd store undefined for a property unless you're willing for null to be the same semantically.
It's not entirely clear if you mean json:
# select '[{"dsad":1},{"sdsad":34.6},{"sdsad":23}]'::json;
json
------------------------------------------
[{"dsad":1},{"sdsad":34.6},{"sdsad":23}]
(1 row)
Or an array of json:
# select array['{"dsad":1}', '{"sdsad":34.6}', '{"sdsad":23}']::json[];
array
------------------------------------------------------
{"{\"dsad\":1}","{\"sdsad\":34.6}","{\"sdsad\":23}"}
(1 row)
Or perhaps hstore? If the latter, it's only for key-values pairs, but you can likewise use an array of hstore values.
You can do something like:
SELECT JSON_AGG(v) FROM mytable v;
However you get something that looks like this:
["00000000-0000-0000-0000-000000000001","00000000-0000-0000-0000-000000000002", "00000000-0000-0000-0000-000000000003"]
exemple :
SELECT title, (select JSON_AGG(v.video_id) FROM videos v WHERE v.channel_id = c.channel_id) AS videos FROM channel AS c
Use text[] myarray insted of myarray text[].