Perform join on multiple tables I have three tables right now in a postgres DB:

Artists             
ID  Name        

Shows
ID  Date    Venue   Price   Is_sold Ages    Time    Multi_day   Pit     

Artists_shows       
ID  Show_id Artist_id


A show can have one or many artists; eventually I'm going to produce JSON for all shows that looks like this:

[
    {
    "bands": [
        "Domino And The Derelicts",
        "Creeper",
        "Lesbros"
    ],
    "date": "2015-12-26T08:00:00.000Z",
    "venue": "Stork Club, Oakland",
    "time": null,
    "soldOut": false,
    "pit": false,
    "multiDay": false,
    "ages": "21+",
    "price": null
    }

...]


Right now I'm doing this pretty inefficiently.

First, I'm running a query: SELECT * FROM shows WHERE date &gt;= ${date} ORDER BY date, where date is today's date.

Then, I'm taking the result and running a for loop through each individual show that results and running this query: SELECT artist.* FROM artist INNER JOIN artist_shows ON artist.id = artist_shows.artist_id AND artist_shows.show_id=${id}, where id is each id from the results of the first query on the Shows table.

I'm then stitching together the results of both queries to produce the resulting JSON.

Is there a way to perform a single JOIN operation on my tables so that I can avoid the loop that I'm running? I assume that there might be a way to merge my existing join with my first query so that I get a table with all of the artists and all of the show details in one table. The thing that is tripping me up is the fact that a show can have many artists associated with it.
You can only return single row results so grouping in the way you are envisioning is not all that natural. There is a way, however, to use aggregate functions to combine groups and get the exact JSON result you are looking for.

SELECT
  row_to_json(all_shows)
FROM (
  SELECT
    array_agg(bands) bands,
    shows.*
  FROM shows
  JOIN (
    SELECT show_id, array_agg(artists.name)
    FROM artist_shows
    JOIN artists ON (artist_shows.artist_id = artists.id)
    GROUP BY show_id
  ) bands ON bands.show_id = shows.id
  WHERE date &gt;= now()
) all_shows


Here we are using a subquery (bands) to group all artists names based on the show id and then join the aggregate array into the show row. Lastly you can combine all rows and return a JSON representation of the data. If you don't care to have Postgres wrap everything up into JSON then you can just use what is in the initial FROM clause.