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?

hfs
  • 2,433
  • 24
  • 37

1 Answers1

5

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)
pozs
  • 34,608
  • 5
  • 57
  • 63
  • Creating a table and column alias at the same time is very interesting, thanks! Where can I find more about this? [The docs](https://www.postgresql.org/docs/12/sql-select.html#id-1.9.3.171.10.5) don't seem to mention it. – Bergi Oct 03 '19 at 21:52
  • @Bergi see https://www.postgresql.org/docs/current/queries-table-expressions.html#QUERIES-TABLEFUNCTIONS -- *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. – pozs Oct 05 '19 at 10:07
  • 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`. – Bergi Oct 05 '19 at 12:21