Search code examples
sqlarrayspostgresqljoinarray-agg

How to make this sql with query array_agg?


I want to make a query

select * from projects where user_id = 3;

and depending on it's result r, I need to make n queries, where n is the length l of r. eg:

| id | project_name | description | user_id |
| 1  | Project A    | lorem ipsu  | 3       |
| 4  | Project B    | lorem ipsu  | 3       |

l => 2 then:

select * from images where project_id = 1;
select * from images where project_id = 4;

Ok, you can see where this is going if l is too big. Too many selects, too many access to the database. Is there a better way to achieve an end result like so:

| id | project_name | description | user_id | images           |
| 1  | Project A    | lorem ipsu  | 3       | {imgX,imgY,imgZ} |
| 4  | Project B    | lorem ipsu  | 3       | {imgA,imgB}      |

I heard about array_agg function on postgres. Maybe that's the answer? Anyways, these are my table descriptions:

                             Table "public.projects"
   Column    |           Type           |                           Modifiers                       
-------------+--------------------------+-------------------------------------------------------
 id          | integer                  | not null default     nextval('projects_id_seq'::regclass)
 name        | character varying(255)   | 
 description | character varying(255)   | 
 user_id     | integer                  | 
 created_at  | timestamp with time zone | 
 updated_at  | timestamp with time zone | 

                                    Table "public.images"
   Column   |           Type           |                      Modifiers                      
------------+--------------------------+-----------------------------------------------------
 id         | integer                  | not null default nextval('images_id_seq'::regclass)
 name       | character varying(255)   | 
 url        | character varying(255)   | 
 project_id | integer                  | 
 created_at | timestamp with time zone | 
 updated_at | timestamp with time zone | 

And thank you in advance :D


Solution

  • array_agg is like any other aggregate function (count, sum), but returns an array instead of a scalar value. What you need can be achieved simply by joining and grouping the 2 tables.

    SELECT p.id, p.name, p.description, p.user_id, array_agg(i.name) images
    FROM projects p
    LEFT JOIN images i ON p.id = i.project_id
    GROUP BY p.id, p.name, p.description, p.user_id