为什么JSONB作为字符串返回?



我已经开始"instagram克隆"后台尝试学习一些关于golang的东西,但是我有一个问题,我不知道如何解决。

我已经建立了一个简单的API与光纤得到一些帖子:

package server
import (
"fmt"
"instagram/internal/psql"
queries "instagram/internal/sql"
"net/http"
"github.com/gofiber/fiber/v2"
)
type Like struct {
Username string
Name     string
picture  string
}
type Post struct {
Id          string `json:"id"`
Description string `json:"description"`
Media       string `json:"media"`
Type        string `json:"type"`
Likes       string `json:"likes"`
User_id     string `json:"user_id"`
Created_at  string `json:"created_at"`
Updated_at  string `json:"updated_at"`
}
func ListPosts(c *fiber.Ctx) error {
rows, err := psql.DB().Query(queries.GetAllPosts)
if err != nil {
c.SendStatus(400)
return nil
}
defer rows.Close()
var data []Post
for rows.Next() {
var post Post
err := rows.Scan(&post.Id, &post.Description, &post.Media, &post.Type, &post.Created_at, &post.Updated_at, &post.Likes, &post.User_id)
if err != nil {
fmt.Print(err)
c.SendStatus(400)
return nil
}
data = append(data, post)
}
return c.Status(http.StatusOK).JSON(data)
}

问题是likes属性作为字符串返回:

[
{
"id": "...",
"description": "...",
"media": "...",
"type": "...",
"likes": "[]",
"user_id": "...",
"created_at": "...",
"updated_at": "..."
}
]

我尝试了一些事情,比如使用json.Marshal(data),我也写了Like结构,但我不能使它工作,因为当我将Likes的类型从string更改为[]Like时,扫描调用时出现以下消息

sql:在列索引6上扫描错误,名称"喜欢":不支持扫描,存储驱动程序。将类型[]uint8转换为类型*[]server。在列索引6上扫描错误,名称"喜欢":不支持扫描,存储驱动程序。将类型[]uint8转换为类型*[]server。像

我使用的是postgresql数据库,我第一次尝试使用jsonb列,所以likes在数据库中是jsonb列。

我理想的有效载荷是这样的:

[
{
"id": "...",
"description": "...",
"media": "...",
"type": "...",
"likes": [],
"user_id": "...",
"created_at": "...",
"updated_at": "..."
}
]

注意likes现在是一个数组而不是字符串。有人知道怎么解吗?

您很可能需要实现sql.Driver的接口以"知道";如何扫描到你的结构体,可能是像

这样的东西
type Like struct {
Username string
Name     string
picture  string
}
type Likes []Like
func (l Likes) Value() (driver.Value, error) {
return json.Marshal(l)
}
// Make the Likes implement the sql.Scanner interface.
func (l *Likes) Scan(value interface{}) error {
b, ok := value.([]byte)
if !ok {
return errors.New("type assertion to []byte failed")
}
return json.Unmarshal(b, &l)
}

可能这只是因为您使用的数据库驱动程序不支持数据类型jsonb

我已经测试了github.com/jackc/pgx/v5包,它可以正确解码jsonb字段。请看下面的例子:

package main
import (
"context"
"log"
"github.com/jackc/pgx/v5"
)
func main() {
// remember to modify the connString below.
connString := "postgres://username:password@localhost:5432/database_name"
conn, err := pgx.Connect(context.Background(), connString)
if err != nil {
log.Fatalf("Unable to connect to database: %vn", err)
}
defer conn.Close(context.Background())
type Like struct {
Name    string
Picture string
}
type Post struct {
Id    string
Likes []Like
}
var post Post
err = conn.QueryRow(context.Background(), `select 'the_id', '[{"name":"a","picture":"a.png"},{"name":"b","picture":"b.png"}]'::jsonb`).Scan(&post.Id, &post.Likes)
if err != nil {
log.Fatalf("QueryRow failed: %vn", err)
}
log.Printf("%#v", post)
}

输出:

main.Post{Id:"the_id", Likes:[]main.Like{main.Like{Name:"a", Picture:"a.png"}, main.Like{Name:"b", Picture:"b.png"}}}