1

Given this tables:

BOOKS

 id | data
----+-------------------------------------------------------
 1  | { title: 'Book 1', price: 10.5, authors: [{ id: 1}, { id: 2 }]}
 2  | { title: 'Book 2', price: 11.5, authors: [{ id: 2 } }

AUTHORS

 id | data
-----+-------------------------------------------------------
 1  | { name: 'Author 1', address: 'Address author 1' }
 2  | { name: 'Author 2', address: 'Address author 2' }

Is it possible to obtain this result, by merging the authors key array elements, with a JOIN-like statement or using jsonb functions?

BOOKS QUERY RESULT

 id | data
----+------------------------------------------------------------------------------------------------------
 1  | { title: 'Book 1', price: 10.5, authors: [{ id: 1, name: 'Author 1', address: 'Address author 1' }, { id: 2, name: 'Author 2', address: 'Address author 2'}] }
 2  | { title: 'Book 2', price: 11.5, authors: [{ id: 2, name: 'Author 2', address: 'Address author 2'}] }

Thanks

3 Answers 3

1

The id arrays have to be unnested and results must be aggregated again what makes the query more complicated. I have changed a bit the arrays structure to more logical.

select b.data || jsonb_build_object('authors', jsonb_agg(a.data || jsonb_build_object('id', a.id)))
from books b
cross join jsonb_array_elements_text(b.data->'authors')
join authors a on a.id = value::int
group by b.id;

SqlFiddle

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks again!! From your answer i managed to get the right answer for my specific case, in which I don't have control over nested "useless" id keys
0

There may be a more elegant way to do this but:

select
    book_id,
    jsonb_set(max(bdata :: text)::jsonb,
              '{authors}',
              jsonb_agg(nested.adata)) as author_data --aggregate authors into one jsonb arr
from (select
          b.id as book_id,
          b.data as bdata,
          a.data as adata
      from books b
      join authors a
          on b.data->'authors' @> concat('[{"id": ', a.id :: varchar, '}]') :: jsonb) as nested
group by book_id;

Relevant docs: see jsonb_set in https://www.postgresql.org/docs/9.5/static/functions-json.html and jsonb_agg at https://www.postgresql.org/docs/9.5/static/functions-aggregate.html

Comments

0
select b.data || jsonb_build_object('authors', jsonb_agg(a.data || 
jsonb_build_object('id', a.id)))
from books b
left join (select id, jsonb_array_elements(data->'authors') from books) ba on 
ba.id = b.id
left join authors a on a.id = ba.id
group by b.id;

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.