postgresql - go-gorm postgres 方言 : managing structs for jsonb insert and find to properly use json tags

标签 postgresql go go-gorm

我做了很多搜索,虽然我可以找到一堆解释如何直接使用 pq 包的好文章。我在 go-gorm 和 postgresql 方言的上下文中不知所措。

如果在 checks.go 中我使用 ChecksMap 它不让我插入但会让我找到。如果我使用 postgres.jsonb 它允许我插入和查询,但找到的记录将是 jsonb。

Gorm 使用指针的结构来确定数据库表和模式。当使用从 API 返回 json 响应的通用 searchHandler 实用程序时,这会引起头痛。对于任何非 jsonb 类型,gorm 使用适当的结构并使用 json 标签,但对于 jsonb,因为它没有对 jsonb 的“结构”的引用,所以它不能使用 json 标签。这会导致返回的 API json 具有大写键。

{
   results: {
      id: "123",
      someId: "456",
      results: [
         {
            Description: "foobar"
         }
      ]
   }
}

是否有一种优雅的方式来处理这类事情,以便 jsonb 结果列具有正确的结构并使用小写的 json 标签?我只是想做一些在 go-gorm 的上下文中不应该做的事情吗?

POSTGRESQL DDL

CREATE TABLE checks (
   id        text,
   some_id   text,
   results   jsonb
);

checks.go

type CheckRules struct {
   Description   string `json:"description"`
}

type ChecksMap   map[string]CheckRules

type Checks struct {
   ID            string           `gorm: "primary_key", json:"id"`
   SomeID        *string          `json:"someId"`
   Results       postgres.jsonb   `json:"results"`                   // <-- this
   // results    ChecksMap        `gorm:"type:jsonb" json:"results"` // <-- or this
}

// func (cm *ChecksMap) Value() (driver.Value, error) {...}
// func (cm *ChecksMap) Scan(val interface{}) error {...}

insertChecks.go

var resultsVal = getResultsValue() // simplified
resJson, _ := json.Marshal(resultsVal)

checks := Checks{
   SomeID: "123",
   Results: postgres.Jsonb{ RawMessage: json.RawMessage(resJson) }
}

err := db.Create(&checks).Error
// ... some error handling

getChecks.go

var checks Checks

err := db.Find(&checks).Error
// ... some error handling

searchHandler.go

func SearchHandler(db *gorm.DB, model, results interface{}) func(c echo.Context) error {
   return func(c echo.Context) error {
      err := db.Find(results).Error
      // ... some error handling

      jsnRes, _ := json.Marshal(results) // <-- uppercase "keys"

      return c.JSON(http.StatusOK, struct {
         Results interface{} `json:"results"`
      }{
         Results: string(jsnRes),
      })
   }
}

最佳答案

您可以使用自定义 ChecksMap 类型,但在其值接收器(而不是指针接收器)上实现driver.Valuer 接口(interface)。

所以,而不是:

func (cm *ChecksMap) Value() (driver.Value, error) { ...

你会这样写:

func (cm ChecksMap) Value() (driver.Value, error) {
    if cm == nil {
        return nil, nil
    }
    return json.Marshal(cm)
}

或者,您可以使它与指针实现一起使用,但是您必须将字段转换为指针,例如:

type Checks struct {
   ID      string     `gorm: "primary_key", json:"id"`
   SomeID  *string    `json:"someId"`
   Results *ChecksMap `json:"results"`
}

(虽然我还没有测试过,所以我不能 100% 确定 gorm 将如何处理这种情况)

关于postgresql - go-gorm postgres 方言 : managing structs for jsonb insert and find to properly use json tags,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57774957/

相关文章:

windows - 努力在 Windows 上构建 Gitea

mysql - golang -> gorm : How I can use sql. NullInt64 在 mysql 中是 int(10)?

postgresql - 使用 GORM 和 Postgresql 时如何在 Go 中节省数据库时间?

python - Postgres 调整 max_connections

没有后端脚本的 Ajax

web - 为简单的 golang web 应用程序添加 ldap 支持的简单方法是什么?

google-app-engine - 通过 GET 参数传递的键获取实体

go - SELECT WHERE with updated_at 是错误的

postgresql - 环回 4 - 字段中包含的 HasMany 关系

postgresql - 为什么 Postgres SQL 函数扫描它不应该扫描的分区