Pat070 Pat070 - 1 year ago 121
JSON Question

Psql function with array of json

I am trying to write a function that has 2 arguments: one array of integers, and one array of JSON

an example of my JSON {[{day:1},{day:2}]}

my function:

create or replace function ctrl_func(theids integer[],thejsons text[])
RETURNS integer AS \$$
i integer;
tj text[];
FOR i IN 1 .. array_upper(theids, 1)
raise notice 'ids %',theids[i];
raise notice 'the jsons %',thejsons[i];
// do other stuff but thejsons fail
\$$ LANGUAGE plpgsql;

Now, I don't understand how to pass the thejsons parameter, I fail miserably in all my trials

Here is what I did

select ctrl_func('{66,67}','{{{{day:1},{day:2}}},{{{day:122},{day:222}}}}');

and the notice message.

NOTICE: ids 66
NOTICE: the jsons <NULL>

I know I am doing something wrong, is it in the passing of parameter or in the selecting thejsons[i] value ? I have been trying a few hours modifying how I pass thejsons, googling like mad, and I cannot find anything that gives me an idea of what to do.

I would be very grateful for any hint, pointer or explanation of what is going on. Thanks in advance

I am adding all my final tests , I have simplified to get the exact problem. I am obviously missing something big somewhere - if anybody can it I would be grateful. Spent part of the night and the whole morning on the docs but no result. Here is what I have so far:

create table tata (json28 jsonb);
insert into tata values('[{"a":2},{"b":3}]');
select * from tata;
[{"a": 2}, {"b": 3}]

my new function :

create or replace function trl_toto(thejsons text[]) RETURNS integer AS $$
js1 text;
js text;
raise notice 'the jsons %',thejsons;
raise notice 'the jsons0 %',to_json(thejsons[1]::text);
select regexp_replace(regexp_replace(thejsons[1]::text,'^{{','['),'}}$',']') into js1;
raise notice 'js1 %',js1;
select regexp_replace(regexp_replace(regexp_replace(js1,'^\"',''),'\"$',''),'\\','','g') into js;
raise notice 'js %',js;
update tata set json28=to_json(js)::jsonb;
return 1;
$$ LANGUAGE plpgsql;

Now I use the function

select trl_toto('{"{{{\"day\":1},{\"day\":2}}}","{{{\"day\":122},{\"day\":222}}}"}');
NOTICE: the jsons {"{{{\"day\":1},{\"day\":2}}}","{{{\"day\":122}, {\"day\":222}}}"}
NOTICE: the jsons0 "{{{\"day\":1},{\"day\":2}}}"
NOTICE: js1 [{"day":1},{"day":2}]
NOTICE: js [{"day":1},{"day":2}]

I check the data in the table

select * from tata;

how can I get rid of the first and last " and of the \" ?
what is wrong when I try to enter js since it has the correct format ?

Answer Source

A json array is a single value of json or jsonb type. There is no reason to use text[] for it, just use jsonb:

create or replace function example_function(jsondata jsonb)
returns void language plpgsql as $$
    raise notice 'json array: %', jsondata;
    raise notice 'json array first element: %', jsondata->0;
end $$;

select example_function('[{"a":1}, {"b":2}]');

NOTICE:  json array: [{"a": 1}, {"b": 2}]
NOTICE:  json array first element: {"a": 1} 

You can use it in a loop with jsonb_array_length():

create or replace function example_function_with_loop(jsondata jsonb)
returns void language plpgsql as $$
    i int;
    raise notice 'json array: %', jsondata;
    for i in 0 .. jsonb_array_length(jsondata)- 1 loop
        raise notice 'element #%: %', i, jsondata->i;
    end loop;
end $$;

select example_function_with_loop('[{"a":1}, {"b":2}]');

NOTICE:  json array: [{"a": 1}, {"b": 2}]
NOTICE:  element #0: {"a": 1}
NOTICE:  element #1: {"b": 2}
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download