gpt4 book ai didi

sql - 高效地将一对多多对多数据库映射到 Golang 中的结构

转载 作者:IT老高 更新时间:2023-10-28 13:09:22 24 4
gpt4 key购买 nike

问题

在 Golang 中处理一对多或多对多 SQL 关系时,将行映射到结构的最佳(高效、推荐、“Go-like”)方式是什么?

以下面的示例设置为例,我试图详细说明一些方法的优缺点,但想知道社区推荐什么。

要求

  • 适用于 PostgreSQL(可以是通用的,但不包括 MySQL/Oracle 特定功能)
  • 效率 - 没有暴力破解每个组合
  • 无 ORM - 理想情况下仅使用 database/sqljmoiron/sqlx

示例

为了清楚起见,我删除了错误处理

模型

type Tag struct {
ID int
Name string
}

type Item struct {
ID int
Tags []Tag
}

数据库

CREATE TABLE item (
id INT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY
);

CREATE TABLE tag (
id INT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
name VARCHAR(160),
item_id INT REFERENCES item(id)
);

方法 1 - 选择所有项目,然后为每个项目选择标签

var items []Item
sqlxdb.Select(&items, "SELECT * FROM item")

for i, item := range items {
var tags []Tag
sqlxdb.Select(&tags, "SELECT * FROM tag WHERE item_id = $1", item.ID)
items[i].Tags = tags
}

优点

  • 简单
  • 简单易懂

缺点

  • 随着数据库查询的数量与项目数量成比例地增加,效率低下

方法 2 - 手动构造 SQL 连接和循环遍历行

var itemTags = make(map[int][]Tag)

var items = []Item{}
rows, _ := sqlxdb.Queryx("SELECT i.id, t.id, t.name FROM item AS i JOIN tag AS t ON t.item_id = i.id")
for rows.Next() {
var (
itemID int
tagID int
tagName string
)
rows.Scan(&itemID, &tagID, &tagName)
if tags, ok := itemTags[itemID]; ok {
itemTags[itemID] = append(tags, Tag{ID: tagID, Name: tagName,})
} else {
itemTags[itemID] = []Tag{Tag{ID: tagID, Name: tagName,}}
}
}
for itemID, tags := range itemTags {
items = append(Item{
ID: itemID,
Tags: tags,
})
}

优点

  • 单个数据库调用和游标,可以循环执行而不会占用太多内存

缺点

  • 在结构上使用多个连接和许多属性来开发复杂且困难
  • 性能不太好;更多的内存使用和处理时间与更多的网络调用

方法 3 失败 - sqlx 结构扫描

尽管失败了,但我想包含这种方法,因为我发现它是我当前的目标,即效率与开发简单性相结合。我希望通过在每个结构字段上显式设置 db 标签 sqlx 可以进行一些高级结构扫描

var items []Item
sqlxdb.Select(&items, "SELECT i.id AS item_id, t.id AS tag_id, t.name AS tag_name FROM item AS i JOIN tag AS t ON t.item_id = i.id")

不幸的是,这错误输出为 missing destination name tag_id in *[]Item 导致我相信 StructScan 不够先进,无法递归循环遍历行(没有批评 -这是一个复杂的场景)

可能的方法 4 - PostgreSQL 数组聚合器和 GROUP BY

虽然我确信这不会工作,但我已经包含了这个未经测试的选项,看看它是否可以改进,以便它可能工作。

var items = []Item{}
sqlxdb.Select(&items, "SELECT i.id as item_id, array_agg(t.*) as tags FROM item AS i JOIN tag AS t ON t.item_id = i.id GROUP BY i.id")

当我有时间时,我会尝试在这里进行一些实验。

最佳答案

postgres 中的 sql:

create schema temp;
set search_path = temp;
create table item
(
id INT generated by default as identity primary key
);

create table tag
(
id INT generated by default as identity primary key,
name VARCHAR(160),
item_id INT references item (id)
);

create view item_tags as
select id,
(
select
array_to_json(array_agg(row_to_json(taglist.*))) as array_to_json
from (
select tag.name, tag.id
from tag
where item_id = item.id
) taglist ) as tags
from item ;


-- golang query this maybe
select row_to_json(row)
from (
select * from item_tags
) row;

然后golang查询这个sql:

select  row_to_json(row)
from (
select * from item_tags
) row;

并解码到结构:

专业人士:

  1. postgres 管理数据的关系。使用 sql 函数添加/更新数据。

  2. golang 管理业务模型和逻辑。

这很简单。

.

关于sql - 高效地将一对多多对多数据库映射到 Golang 中的结构,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54601529/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com