【问题标题】:Go SQL map 1:M relation json array to sliceGo SQL map 1:M 关系 json 数组切片
【发布时间】:2020-10-31 06:30:30
【问题描述】:

我有一个product-image (1:M) 关系,基本上我想将这些图像映射到我的结构中的一个切片。我正在使用 sqlx 库使它更容易一些。

我搜索了一段时间,也许最好的答案在这个帖子中:Efficiently mapping one-to-many many-to-many database to struct in Golang。 创建视图并以 json 格式返回所有内容的答案是可行的,但感觉有点 hacky。

理想情况下,我想做的是使用 postgres json_agg 在 images 列中返回与我的类型匹配的 json 数组,以便我可以扫描到它。

我用 nodejs 做了几次,但我不知道怎么做。我需要实现自定义Scan 和Value 方法还是有更简单的方法。我没有展示这个,但我也有一个 1:1 的类别,我可以将该类别嵌入到产品中并进行左连接,它适用于 sqlx,但不适用于图像类型。

简化模型

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"`
}

数据库表

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)
);

我现在正在尝试这样的事情:

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)
}

我收到此错误:

sql: Scan error on column index 26, name "images": unsupported Scan, storing driver.Value type []uint8 into type *model.ImageList

这似乎是一个超级常见的场景,但我找不到任何例子...... 或者最后我这样做是不是很愚蠢,因为我可以在 JS 中执行 forEach 并执行 50 个查询来获取每个产品的所有图像。

【问题讨论】:

  • 只是好奇,如果product_image 行与ON p.id = img.product_id 连接,过滤器where 子句WHERE img.product_id IS NOT NULL 是否会导致false?不是没有必要吗?
  • 您可以为*ImageList 实现sql.Scanner 接口,让实现类型断言interface{} 参数到[]byte,然后将其结果与接收者一起传递给json.Unmarshal。即play.golang.org/p/Zh50aAB3YA1
  • @mkopriva 我试过了,但实际上我得到了同样的错误,很有趣。无论如何感谢您的帮助。对于查询,如果我不编写过滤器,它实际上给了我这样的数组,里面有 null。 [空值]。我想还有其他方法可以做到这一点,但这个查询有效。

标签: postgresql go struct sqlx


【解决方案1】:

使用此映射库可以完成获取项目列表的一种解决方案:carta

q := `SELECT p.*, img.id AS img_id, img.url AS img_url 
      FROM public.product p
      LEFT JOIN product_image img ON p.id = img.product_id`

    rows, err := sqlxdb.Query(q)
    if err != nil {
        fmt.Println(err)
    }

    var products []*model.Product
    carta.Map(rows, &products)

对于 img 结构,我会使用 db:"img_id" 前缀等等,因为我选择别名...

【讨论】:

    猜你喜欢
    • 2012-11-10
    • 1970-01-01
    • 1970-01-01
    • 2020-01-14
    • 2020-08-17
    • 1970-01-01
    • 1970-01-01
    • 2018-08-02
    • 1970-01-01
    相关资源
    最近更新 更多