I have a product-image (1:M) relation and basically i want to map those images to a slice in my struct. I am using sqlx library to make it bit easier.
I searched for a while and maybe the best answer was in this thread: Efficiently mapping one-to-many many-to-many database to struct in Golang. The answer with creating the view and returning everything as a json works but it feels somehow hacky.
Ideally what i want to do is use postgres json_agg to return the json array inside the images column that would match my type so i could scan into it.
I did this with nodejs several times but here i don't know how. Do i need to implement custom Scan and Value methods or is there a simpler way. I didn't show this but i also have a category that is 1:1 and i can embed that category in product and do a left join and it works with sqlx, but not with images type.
Simplified models
type Image struct {
ID int,
URL string,
ProductID int
}
type ImageList []*Image
type Product struct {
ID int `db:"id"`
Name string `db:"name"`
Images ImageList `db:"images"`
}
DB Tables
create table product (
id int generated always as identity primary key,
name varchar(255),
);
create table product_image (
id int generated always as identity primary key,
url text not null,
product_id int references product(id)
);
I am trying something like this now:
q := `SELECT
p.*,
COALESCE(JSON_AGG(img.*) FILTER (WHERE img.product_id IS NOT NULL), '[]'::json) AS images
FROM product p
LEFT JOIN product_image img ON p.id = img.product_id
WHERE p.id = 1
GROUP BY p.id`
var p Product
if err := sqlxdb.Get(&p, q); err != nil {
fmt.Printf("Error: %v\n", err)
}
I get this error:
sql: Scan error on column index 26, name "images": unsupported Scan, storing driver.Value type []uint8 into type *model.ImageList
This seems like a super common scenario and yet i can't find any examples... Or finally am i even stupid for doing this because i can just do forEach in JS and do like 50 queries to fetch all the images for every product.
product_imagerow is joined withON p.id = img.product_idwould the filter where clauseWHERE img.product_id IS NOT NULLever result infalse? Isn't it unnecessary?sql.Scannerinterface for*ImageList, have the implementation type-assert theinterface{}argument to[]byteand then pass the result of that, together with the receiver, tojson.Unmarshal. i.e. play.golang.org/p/Zh50aAB3YA1[]uint8column data for a Postgres array type has a specific format that needs to be parsed. Once parsed you'd have a[][]bytethat could then be used to pass each element tojson.Unmarshal.