GoLang如何对PostgreSQL行内的对象数组执行读写操作?
解决方案
以下方案默认你使用关系型数据库,采用一对多表结构:posts表存储文章基础信息,comments表存储评论,包含post_id外键关联对应文章ID。如果你是将评论以JSON字段形式直接存在posts表中,可参考各部分的JSON适配方案。
1. 查询Post列表时同步加载关联Comments
小数据量场景(简单实现)
在原有查询逻辑中,每遍历到一篇Post,就查询它关联的所有评论组装进去,修改后代码如下:
OpenDB() defer CloseDB() // 新增defer避免数据库连接泄漏 rows, err := cn.Query(`SELECT id, date, title, special, content, image FROM posts ORDER BY date DESC LIMIT $1 OFFSET $2`, limit, offset) // 不需要转字符串,数据库驱动支持直接传数值类型 if err != nil { panic(err) } defer rows.Close() posts := []Post{} for rows.Next() { post := Post{} e := rows.Scan(&post.Id, &post.Date, &post.Title, &post.Special, &post.Content, &post.Image) if e != nil { panic(e) } // 新增:查询当前Post关联的所有评论 commentRows, err := cn.Query(`SELECT id, user, email, date, comment FROM comments WHERE post_id = $1 ORDER BY date ASC`, post.Id) if err != nil { panic(err) } defer commentRows.Close() comments := []Comment{} for commentRows.Next() { c := Comment{} e := commentRows.Scan(&c.Id, &c.User, &c.Email, &c.Date, &c.Comment) if e != nil { panic(e) } comments = append(comments, c) } post.Comments = comments posts = append(posts, post) }
大数据量场景(避免N+1查询)
用LEFT JOIN一次性查询所有Post和关联评论,再按Post ID分组组装,减少数据库IO次数:
rows, err := cn.Query(` SELECT p.id, p.date, p.title, p.special, p.content, p.image, c.id, c.user, c.email, c.date, c.comment FROM posts p LEFT JOIN comments c ON p.id = c.post_id ORDER BY p.date DESC, c.date ASC LIMIT $1 OFFSET $2 `, limit, offset) // 后续遍历结果集,按Post ID去重,把同属一个Post的评论组装到对应Comments字段即可
JSON字段存储适配方案
如果posts表用PostgreSQL JSONB类型存储comments字段,直接查询该字段后反序列化即可:
rows, _ := cn.Query(`SELECT id, date, title, special, content, image, comments FROM posts ORDER BY date DESC LIMIT $1 OFFSET $2`, limit, offset) for rows.Next() { var commentJson json.RawMessage post := Post{} e := rows.Scan(&post.Id, &post.Date, &post.Title, &post.Special, &post.Content, &post.Image, &commentJson) if e != nil { panic(e) } _ = json.Unmarshal(commentJson, &post.Comments) posts = append(posts, post) }
2. 插入Post时初始化空Comments
独立评论表场景
不需要修改原有INSERT逻辑,新插入的Post没有关联评论,代码中直接初始化post.Comments = []Comment{}即可得到空数组。
JSON字段存储适配方案
修改INSERT语句,新增comments字段传入空JSON数组即可:
OpenDB() defer CloseDB() _, e = cn.Exec(`INSERT INTO posts(date, title, special, content, image, comments) VALUES ($1, $2, $3, $4, $5, $6)`, date, title, special, content, image, []byte("[]")) if e != nil { panic(e) }
3. 向已存在的Post写入单条Comment
独立评论表场景
直接向comments表插入关联对应Post ID的评论记录即可:
// 参数为目标Post的ID和待插入的Comment对象 func AddComment(postId int, comment Comment) error { OpenDB() defer CloseDB() _, err := cn.Exec(`INSERT INTO comments(post_id, user, email, date, comment) VALUES ($1, $2, $3, $4, $5)`, postId, comment.User, comment.Email, comment.Date, comment.Comment) return err }
JSON字段存储适配方案
用PostgreSQL的JSON操作符追加评论到对应数组中:
commentJson, _ := json.Marshal(comment) _, err := cn.Exec(`UPDATE posts SET comments = comments || $1::jsonb WHERE id = $2`, commentJson, postId)
内容的提问来源于stack exchange,提问作者chevi
相关产品推荐
相关产品推荐

