postgresql - 解码从 postgresql 获得的对象的 Json 数组

标签 postgresql go

我在 Postgres 中有一个 Jsonb 表

Create Table Business(
    id serial not null primary key,
    id_category integer not null,
    name varchar(50) not null,
    owner varchar(200) not null,
    coordinates jsonb not null,
    reason varchar(300) not null,
    foreign key(id_category) references Category(id)
);

如您所见,我存储坐标jsonb

例如:

Insert into Business(id_category, name, owner, coordinates, reason) 
values 
(1,'MyName','Owner', [{"latitude": 12.1268142, "longitude": -86.2754}]','Description')

我提取数据并分配它的方式是这样的。

type Business struct {
    ID int `json:"id,omitempty"`
    Name string `json:"name,omitempty"`
    Owner string `json:"owner,omitempty"`
    Category string `json:"category,omitempty"`
    Departments []string `json:"departments,omitempty"`
    Location []Coordinates `json:"location,omitempty"`
    Reason string `json:"reason,omitempty"`
}

type Coordinates struct {
    Latitude float64 `json:"latitude,omitempty"`
    Longitude float64 `json:"longitude,omitempty"`
}

func (a Coordinates) Value() (driver.Value, error) {
    return json.Marshal(a)
}

func (a *Coordinates) Scan(value []interface{}) error {
    b, ok := value.([]byte)
    if !ok {
        return errors.New("type assertion to []byte failed")
    }
    return json.Unmarshal(b, &a)
}

但是,我不断收到此消息。

sql: Scan error on column index 3, name "coordinates": unsupported Scan, storing driver.Value type []uint8 into type *models.Coordinates

我用来提取信息的 Controller 就是这个。

func (b *BusinessRepoImpl) Select() ([]models.Business, error) {
    business_list := make([]models.Business, 0)
    rows, err := b.Db.Query("SELECT business.id, business.name, business.owner, business.coordinates, business.reason_froggy, category.category FROM business INNER JOIN category on category.id = business.id_category group by business.id, business.name, business.owner, business.coordinates, business.reason_froggy, category.category")
    if err != nil {
        return business_list, err
    }
    for rows.Next() {
        business := models.Business{}
        err := rows.Scan(&business.ID, &business.Name, &business.Owner, &business.Location, &business.Reason, &business.Category)
        if err !=  nil {
            break
        }
        business_list = append(business_list, business)
    }
    err = rows.Err()
    if err != nil {
        return business_list, err
    }
    return business_list, nil
}

谁能告诉我如何解决这个问题?检索对象的 json 数组并将其分配给 Business 中的坐标字段。

最佳答案

1.

正如您从文档中看到的 Scanner接口(interface),要满足,需要方法

Scan(src interface{}) error

但是您的*Coordinates 类型实现了不同的方法

Scan(value []interface{}) error

类型 interface{}[]interface{} 是两种截然不同的东西。

2.

必须在要作为参数传递给 rows.Scan 的字段类型上实现 Scanner 接口(interface).也就是说,您已经在 *Coordinates 上实现了 Scan 方法,但是 Location 字段的类型是 []Coordinates

同样,类型*Coordinates[]Coordinates 是两种截然不同的东西。


因此解决方案是在正确的类型上正确地实现接口(interface)。

请注意,由于 Go 不允许向未命名类型添加方法,并且 []Coordinates 是未命名类型,因此您需要声明一个新类型然后将使用 []Coordinates

type CoordinatesSlice []Coordinates

func (s *CoordinatesSlice) Scan(src interface{}) error {
    switch v := src.(type) {
    case []byte:
        return json.Unmarshal(v, s)
    case string:
        return json.Unmarshal([]byte(v), s)
    }
    return errors.New("type assertion failed")
}

// ...

type Business struct {
    // ...
    Location CoordinatesSlice `json:"location,omitempty"`
    // ...
}

注意

如果业务位置始终只有一对坐标作为 jsonb 对象存储到数据库中,则将 Location 类型从 CoordinatesSliceCoordinates 并相应地将 Scanner 实现从 *CoordinatesSlice 移动到 *Coordinates

关于postgresql - 解码从 postgresql 获得的对象的 Json 数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58633251/

相关文章:

PostgreSQL 触发器和异常

go - 将 curl -F 转换为 golang

go - 来自流的字符串用于多种对象类型

postgresql - 当生成器策略设置为 IDENTITY 时无法设置 sequenceGenerator

ruby-on-rails - 如何使用连接表的 bool 列使 Rails/ActiveRecord 返回唯一对象

postgresql - PostGis Multipolygon ERROR - 纵坐标太少

php - 如何连接到 heroku postgres 数据库?

parsing - 如何在 Go 中解码和编码 YAML,同时保留空白?

casting - golang 将字符串转换为 net.IPNet 类型

Golang : Why does strings. Builder.WriteByte API 提示它可以返回错误?