The question contains inaccuracies: the expected result is not a valid json and the table is not properly defined.
Assume that the table definition is:
create table the_table
(
id integer,
some_name text, -- do not use 'name' for column name
descr text, -- 'desc' is invalid column name
object_id integer,
lang text -- do not use 'language' for column name
)
The query:
select json_agg(json_build_object('object_id', object_id, 'text', js))
from (
select object_id, json_agg(js) js
from (
select
object_id,
lang,
json_build_object(
lang,
json_object(array['name', some_name, 'desc', descr])
) js
from the_table
order by lang
) alias
group by 1
) alias
produces this valid json.
Postgres 9.3 solution
Postgres 9.4 came with a powerful function json_build_object(variadic "any")
.
It is impossible to substitute it with your own function because plpgsql does not allow variadic "any"
as an argument.
For the purposes of Postgres 9.3 we will use three functions that operate on text type (rather than on json), and the simplest aggregate function string_agg
(this solution is sufficient, although more elegant would be to define our own aggregate function).
create function js_clear(t text)
returns text language sql as $$
select replace(replace(replace(replace(t,'"[','['), '"{','{'), '}"','}'), ']"',']');
$$;
create function js_array(t text)
returns text language sql as $$
select format('[%s]', js_clear(t));
$$;
create function js_object(variadic args text[])
returns text language plpgsql as $$
declare
res text = '';
begin
for i in 1 .. array_length(args, 1) by 2 loop
res:= format('%s"%s" : "%s", ', res, args[i], args[i+1]);
end loop;
return format('{%s}', rtrim(js_clear(res), ', '));
end $$;
The query in 9.3 version:
select js_array(string_agg(js_object('object_id', object_id::text, 'text', js), ', '))
from (
select object_id, js_array(string_agg(js, ', ')) js
from (
select
object_id,
lang,
js_object(
lang,
js_object('name', some_name, 'desc', descr)
) js
from the_table
order by lang
) alias
group by 1
) alias