I've come up with the following query, wonder if you meant something similar -
WITH cte1 AS (SELECTmid,STRING_AGG(x->>'letter', '') AS tilesFROM (SELECTmid,JSONB_ARRAY_ELEMENTS(m.tiles) AS xFROM moves mWHERE m.gid = 1) AS zGROUP BY mid),cte2 AS (SELECTmid,STRING_AGG(y, ', ') AS wordsFROM (SELECTmid,FORMAT('%s (%s)', s.word, s.score) AS yFROM scores sWHERE s.gid = 1) AS zGROUP BY mid)SELECT mid, tiles, wordsFROM cte1 JOIN cte2 using (mid) ORDER BY mid ASC;
Yes. It does end up presuming that the sets moves.mid and scores.mid are identical but that is probably a safe assumption. Repetition of m.gid = 1 is worth avoiding in theory though depending on how its done the solution can be worse than the problem (if the planner ends up unable to push the predicate down).
David J.