Golang使用sqlc生成带嵌套数组的结构体失败求助
在Golang中用sqlc和PostgreSQL实现带嵌套分类数组的产品列表问题
我在Golang项目里用sqlc配合PostgreSQL,想要实现返回包含嵌套产品分类数组的产品列表功能,试了几种方法都没解决,具体情况如下:
表结构
create table products ( id serial primary key, title text unique not null, url text ); create table product_categories ( id serial primary key, title text unique not null, product_id integer not null constraint products_id_fk references products (id), url text );
尝试过的方案与问题
方案1:直接关联查询
使用如下查询语句:
select p.*, sqlc.embed(pc) from products p join product_categories pc on pc.product_id = p.id
期望生成的结构体:
type GetAllProductsAndSubcatsRow struct { ID int32 `db:"id" json:"id"` Title string `db:"title" json:"title"` Url pgtype.Text `db:"url" json:"url"` ProductCategory []ProductCategory `db:"product_category" json:"product_category"` }
实际生成的结构体:
type GetAllProductsAndSubcatsRow struct { ID int32 `db:"id" json:"id"` Title string `db:"title" json:"title"` Url pgtype.Text `db:"url" json:"url"` ProductCategory ProductCategory `db:"product_category" json:"product_category"` }
问题:sqlc将关联后的每一行结果映射为单个对象,不会自动把同一产品的多个分类聚合为数组。
方案2:使用array_agg函数
尝试用array_agg聚合分类,生成的结构体中分类字段变成了interface{},无法直接使用:
type GetAllProductsAndSubcatsRow struct { ID int32 `db:"id" json:"id"` Title string `db:"title" json:"title"` Url pgtype.Text `db:"url" json:"url"` ProductCategory interface{} `db:"product_category" json:"product_category"` }
问题:PostgreSQL的array_agg默认返回匿名复合类型数组,sqlc无法识别为自定义的ProductCategory结构体,只能推断为interface{}。
错误原因分析
- 直接关联查询返回的是平级多行数据,每个产品对应多条分类记录,sqlc按行映射结构体,自然会把分类字段处理为单个对象。
array_agg聚合匿名复合类型时,sqlc没有足够的类型信息来映射到自定义结构体,只能 fallback 到interface{}。
解决方法
方法1:用json_agg+sqlc类型映射
这是最简便的方案,利用PostgreSQL的json_agg将分类转为JSON数组,再通过sqlc的类型映射把JSON数组绑定到[]ProductCategory。
步骤1:修改查询语句
select p.id, p.title, p.url, json_agg(pc) as product_categories from products p join product_categories pc on pc.product_id = p.id group by p.id, p.title, p.url
注意:必须用
group by聚合产品的所有非聚合字段,否则PostgreSQL会报错。
步骤2:配置sqlc类型映射
在你的sqlc.yaml配置文件中,添加JSON数组到[]ProductCategory的类型映射:
sql: - schema: "schema.sql" # 你的表结构文件路径 queries: "queries.sql" # 你的查询语句文件路径 engine: "postgresql" gen: go: out: "internal/db" # 生成代码的输出目录 overrides: - db_type: "jsonb" go_type: type: "[]ProductCategory" import: "your/project/path/to/db" # 替换为ProductCategory结构体所在的包路径
这样sqlc就能把json_agg返回的JSON数组正确映射为[]ProductCategory类型。
方法2:自定义PostgreSQL类型+array_agg
如果不想用JSON,可通过自定义PostgreSQL类型让sqlc识别聚合后的数组类型。
步骤1:创建自定义类型
create type product_category_type as ( id int, title text, product_id int, url text );
步骤2:修改查询语句
select p.*, array_agg(pc::product_category_type) as product_categories from products p join product_categories pc on pc.product_id = p.id group by p.id, p.title, p.url
步骤3:配置sqlc类型映射
在sqlc.yaml中添加自定义类型数组到[]ProductCategory的映射:
sql: - schema: "schema.sql" queries: "queries.sql" engine: "postgresql" gen: go: out: "internal/db" overrides: - db_type: "product_category_type[]" go_type: type: "[]ProductCategory" import: "your/project/path/to/db"
内容的提问来源于stack exchange,提问作者Anton Bychek
相关产品推荐
相关产品推荐

