Golang:将嵌套结构模型插入到Postgres中

huangapple go评论69阅读模式
英文:

Golang: insert nested structure model into Postgres

问题

我有这个模型数据结构:

type Order struct {
	OrderEntry OrderEntry `db:"order"`
}

type OrderEntry struct {
	Order_uid          string
	Track_number       string
	Entry              string
	Delivery           Delivery
	Payment            Payment
	Items              []Item
	Locale             string
	Internal_signature string
	Customer_id        string
	Delivery_service   string
	Shardkey           string
	Sm_id              int64
	Date_created       string
	Oof_shard          string
}

type Delivery struct {
	// ...
}

type Payment struct {
	// ...
}

type Item struct {
	// ...
}

我有一个表:

CREATE TABLE "order"
(
    "order" jsonb NOT NULL
);

我如何将Order对象插入到这个psq表中?我使用sqlx,但是在这段代码中我遇到了错误:

func (r *RepositoryPostgres) CreateDocument(order L0.Order) error {
	tx := r.db.MustBegin()
	tx.MustExec("INSERT INTO order (order) VALUES ($1)", order.OrderEntry)
	err := tx.Commit()

	if err != nil {
		return err
	}

	return nil
}

错误信息为:panic: sql: converting argument $1 type: unsupported type L0.OrderEntry, a struct

如何正确修复这个问题?谢谢。

英文:

i have this model data structure:

type Order struct {
	OrderEntry OrderEntry `db:"order"`
}

type OrderEntry struct {
	Order_uid          string
	Track_number       string
	Entry              string
	Delivery           Delivery
	Payment            Payment
	Items              []Item
	Locale             string
	Internal_signature string
	Customer_id        string
	Delivery_service   string
	Shardkey           string
	Sm_id              int64
	Date_created       string
	Oof_shard          string
}

type Delivery struct {
	...
}

type Payment struct {
	...
}

type Item struct {
	...
}

And i have table

CREATE TABLE "order"
(
    "order" jsonb NOT NULL
);

How do i insert Order object to this psq table? I use sqlx and for this code im getting error

func (r *RepositoryPostgres) CreateDocument(order L0.Order) error {
	tx := r.db.MustBegin()
	tx.MustExec("INSERT INTO order (order) VALUES ($1)", order.OrderEntry)
	err := tx.Commit()

	if err != nil {
		return err
	}

	return nil
}

panic: sql: converting argument $1 type: unsupported type L0.OrderEntry, a struct

How to properly fix this? Thanks

答案1

得分: 3

这里有几个你需要做的更改。

  1. 你需要将要存储的结构体转换为 JSON 格式。你可以使用以下代码实现:
orderB, err := json.Marshal(order.OrderEntry)
if err != nil {
    // 处理错误
}

tx.MustExec("INSERT INTO order (order) VALUES ($1)", orderB)

这样会将你的结构体以 JSON 字节数组的形式存储到表中。

  1. 为了正确地从结构体生成 JSON,你需要为每个字段添加 JSON 结构标签。例如:
type OrderEntry struct {
    Order_uid          string `json:"order_uid"`
    Track_number       string `json:"track_number"`
    Entry              string `json:"entry"`
    Delivery           Delivery `json:"delivery"`
    Payment            Payment `json:"payment"`
    Items              []Item `json:"items"`
    Locale             string `json:"locale"`
    Internal_signature string `json:"internal_signature"`
    Customer_id        string `json:"customer_id"`
    Delivery_service   string `json:"delivery_service"`
    Shardkey           string `json:"shard_key"`
    Sm_id              int64  `json:"sm_id"`
    Date_created       string `json:"date_created"`
    Oof_shard          string `json:"oof_shard"`
}

你可以根据需要自定义这些标签,通常使用蛇形命名法。这些标签为解析器提供了 JSON 字段的名称。

如果没有这些标签,你将得到一个空的 JSON,并且无法检索数据。

英文:

There are a couple of changes you need to make here.

  1. You need to marshal to JSON the struct you want to store. You can do that with:
orderB, err := json.Marshal(order.OrderEntry)
if err != nil {
    // handle err
}

tx.MustExec("INSERT INTO order (order) VALUES ($1)", orderB)

This will now store your struct as a JSON byte-array in the table.

  1. In order to generate JSON from your struct correctly, you need to add JSON struct tags to each field. e.g.:
type OrderEntry struct {
    Order_uid          string `json:"order_uid"`
    Track_number       string `json:"track_number"`
    Entry              string `json:"entry"`
    Delivery           Delivery `json:"delivery"`
    Payment            Payment `json:"payment"`
    Items              []Item `json:"items"`
    Locale             string `json:"locale"`
    Internal_signature string `json:"internal_signature"`
    Customer_id        string `json:"customer_id"`
    Delivery_service   string `json:"delivery_service"`
    Shardkey           string `json:"shard_key"`
    Sm_id              int64 `json:"sm_id"`
    Date_created       string `json:"date_created"`
    Oof_shard          string `json:"oof_shard"`
}

You can name these however you like, snake-case being the common format. These tags provide the names for the JSON fields to the parser.

Without these fields, you'll end up with empty JSON, and you won't be able to retrieve the data.

答案2

得分: 2

INSERT语句中不支持的类型"L0.OrderEntry"是导致你遇到问题的原因。由于"L0.OrderEntry"是"L0.Order"中的嵌套结构体,所以不能直接将其输入到JSONB列中。在将OrderEntry对象输入到表中之前,你需要将其转换为JSON表示。

你可以按照以下方式更改代码以解决错误。

import "encoding/json"

func (r *RepositoryPostgres) CreateDocument(order L0.Order) error {
    tx := r.db.MustBegin()

    orderJSON, error := json.Marshal(order.OrderEntry)
    if error != nil {
        return error
    }

    tx.MustExec("INSERT INTO order (order) VALUES ($1)", orderJSON)
    error = tx.Commit()

    if error != nil {
        return error
    }

    return nil
}

修改后的代码使用"json.Marshal"方法将order.OrderEntry对象转换为JSON。生成的JSON字节切片(orderJSON)然后作为值提供给INSERT语句。

通过将嵌套结构体转换为JSON,你可以确保数据以正确的格式插入到JSONB列中。

英文:

The INSERT statement's unsupported type "L0.OrderEntry" is the cause of the issue you're experiencing. "L0.OrderEntry" cannot be directly entered into the JSONB column since it is a nested struct within "L0.Order". Instead, before entering the OrderEntry object into the table, you must marshal it into a JSON representation.

You can change your code as below to resolve the error.

    import "encoding/json"

    func (r *RepositoryPostgres) CreateDocument(order L0.Order) error {
    tx := r.db.MustBegin()

    orderJSON, error := json.Marshal(order.OrderEntry)
    if error != nil {
      return error
    }

    tx.MustExec("INSERT INTO order (order) VALUES ($1)", orderJSON)
    error = tx.Commit()

    if error != nil {
     return error
    }

     return nil
    }

The order.OrderEntry object is marshalled into JSON in the modified code using the "json.Marshal" method. The generated JSON byte slice (orderJSON) is then provided to the INSERT statement as the value.

You may make sure the data is in the correct format for insertion into the JSONB column by marshalling the nested struct into JSON.

huangapple
  • 本文由 发表于 2023年6月25日 08:12:40
  • 转载请务必保留本文链接:https://go.coder-hub.com/76548421.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定