3

I can create JSON objects using jsonb_build_object the way I want them. E.g.

SELECT jsonb_build_object('id', id) FROM (SELECT generate_series(1,3) id) objects;

results in

jsonb_build_object
------------------
{"id": 1}
{"id": 2}
{"id": 3}

But when I want to add them to an array, they are wrapped in an additional object, using the column name as key:

SELECT jsonb_build_object(
  'foo', 'bar',
  'collection', jsonb_agg(collection)
)
FROM (
  SELECT jsonb_build_object('id', id)
  FROM (
    SELECT generate_series(1,3) id
  ) objects
) collection;

results in

{"foo": "bar", "collection": [{"jsonb_build_object": {"id": 1}}, {"jsonb_build_object": {"id": 2}}, {"jsonb_build_object": {"id": 3}}]}

How can I get

{"foo": "bar", "collection": [{"id": 1}, {"id": 2}, {"id": 3}]}

instead?

1

1 Answer 1

6

Use jsonb_agg(collection.jsonb_build_object). You can use aliases too, but the point is that collection refers to the entire row, which has a (single) jsonb_build_object named (by default) column, which is the JSON you want to aggregate.

With simplifying and aliases, you query can be:

SELECT     jsonb_build_object(
             'foo', 'bar',
             'collection', jsonb_agg(js)
           )
FROM       generate_series(1,3) id
CROSS JOIN LATERAL jsonb_build_object('id', id) js;

Notes:

  • LATERAL is implicit, I just wrote it for clarity
  • aliasing like this in the FROM clause creates a table & a column alias too, with the same name. So it is equivalent to jsonb_build_object('id', id) AS js(js)
Sign up to request clarification or add additional context in comments.

3 Comments

Creating a table and column alias at the same time is very interesting, thanks! Where can I find more about this? The docs don't seem to mention it.
@Bergi see postgresql.org/docs/current/… -- If column aliases are not supplied, then for a function returning a base data type, the column name is also the same as the function name. For a function returning a composite type, the result columns get the names of the individual attributes of the type. -- although it is only implied that when you are aliasing the function name, the default column name changes with it.
Ah. I guess I was more confused by referring to the table_alias element in the syntax as a "function name" :-) I thought using fn(…) AS t would create a table t with a column fn.

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.