go-gorm postgres 方言:管理 jsonb 插入和查找的结构以正确使用 json 标签

做了很多搜索,尽管我可以找到很多很好的文章来解释如何直接使用 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

);

检查.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

搜索处理程序


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),

      })

   }

}


拉丁的传说
浏览 223回答 1
1回答

米脂

您可以使用自定义类型,但在其值接收器而不是指针接收器上ChecksMap实现接口。driver.Valuer所以,而不是:func (cm *ChecksMap) Value() (driver.Value, error) { ...你会这样写:func (cm ChecksMap) Value() (driver.Value, error) {&nbsp; &nbsp; if cm == nil {&nbsp; &nbsp; &nbsp; &nbsp; return nil, nil&nbsp; &nbsp; }&nbsp; &nbsp; return json.Marshal(cm)}或者,您可以使其与指针实现一起使用,但随后您必须将该字段转换为指针,例如:type Checks struct {&nbsp; &nbsp;ID&nbsp; &nbsp; &nbsp; string&nbsp; &nbsp; &nbsp;`gorm: "primary_key", json:"id"`&nbsp; &nbsp;SomeID&nbsp; *string&nbsp; &nbsp; `json:"someId"`&nbsp; &nbsp;Results *ChecksMap `json:"results"`}(虽然我还没有测试过,所以我不能 100% 确定 gorm 将如何处理这种情况)
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go