Reputation: 2787
Consider the following tables
CREATE TABLE foo (
id INT PRIMARY KEY
)
CREATE TABLE bar (
id INT PRIMARY KEY
)
CREATE TABLE foo_bar_members (
foo_id INT NOT NULL REFERENCES foo(id) ON DELETE CASCADE ON UPDATE CASCADE,
bar_id INT NOT NULL REFERENCES bar(id) ON DELETE CASCADE ON UPDATE CASCADE,
PRIMARY KEY (foo_id, bar_id)
)
foo_bar_members
is a relations table that connects foo
and bar
. View foo
as the parent of bar
. And I have the following Go struct:
type Foo struct {
ID int `db:"id"`
BarIDs []int
}
BarIDs
is a slice of bar.id
that is associated with this foo
by foo.id
. I want to query for something like this:
SELECT * FROM foo f INNER JOIN foo_bar_members fbm ON f.id = fbm.foo_id WHERE f.id = $1
But this query is just an example. Obvious this won't scan into Foo.BarIDs
. I could always do two separate queries but I'm wondering if there are better ways. I'm using sqlx.
Upvotes: 0
Views: 2540
Reputation: 38233
The SQL, the left join here will also return foos that don't have no bars associated.
select
foo.id
, array_agg(bar.id)
from foo
left join foo_bar_members m on m.foo_id = foo.id
where foo.id = $1
group by foo.id
If you care only about foos that have bars, then there's no need for the join actually.
select
m.foo_id
, array_agg(m.bar_id)
from foo_bar_members m
where m.foo_id = $1
group by m.foo_id
The go code:
const sql = "<one of the queries from above>"
f := new(Foo)
if err := db.QueryRow(sql, 123).Scan(&f.ID, pq.Array(&f.BarIDs)); err != nil {
return err
}
pq.Array
is a function that returns a value that implements the sql.Scanner
and driver.Valuer
interfaces and the implementation knows how to scan a postgres array into a go slice or turn a go slice into a postgres array.
I'm not familiar with sqlx
so it's possible it itself provides some feature that allows you to scan arrays and therefore the use of pq.Array
might be unnecessary. Maybe someone who know better will eventually provide their version of the solution.
Upvotes: 1