【问题标题】:Update columns which included in payload更新有效载荷中包含的列
【发布时间】:2018-03-31 05:07:31
【问题描述】:

我有一个到 mysql 表的结构映射,如下所示,并且想要更新在 PUT 请求有效负载中发送的字段

type Notification struct {
 Id                 int64     `json:"id"`
 Type               NotificationType
 Subject            string    `json:"confidence"`
 Body               string    `json:"body"`
 CreatedDate        time.Time `json:"created_dt"`
 CreatedBy          int64     `json:"created_by"`
 ParentNotification int64     `json:"parent_id"`
 IsExpired          bool      `json:"expired"`
}

目前我要求所有字段都包含在有效负载中,即使数据没有更改,并使用带有 db.Exec(query) 语句的查询更新所有列。

有什么方法可以让客户只包含在有效负载中更改的字段并仅更新这些字段?

{
 "body" : "new body"
 "subject" : "new subject"
}

我正在数据库端使用以下包。

"database/sql"
_ "github.com/go-sql-driver/mysql"

【问题讨论】:

  • “要求客户端仅包含有效负载中更改的字段并仅更新这些字段”是什么意思?您想要一种发送请求的方法还是如何处理请求?
  • 客户端程序可以将一个字段作为有效负载发送,也可以将所有字段作为有效负载发送,并且在 htt 处理程序中我需要更新他们发送的字段。如果有效负载是 {"body" : "newbody"} -那么 query = "update tbl set body="newbody" where id = id 。如果有效负载是 {"subject" : "new", "body" : "new"}然后查询 =“更新 tbl 设置主题 =“新”,身体 =“新”,其中 id = 1
  • 您只需将负载解码为 Notification 结构并根据您的应用逻辑验证此结构,然后使用非空字段相应地更新数据库。

标签: mysql rest go


【解决方案1】:

一种做你想做的事情的方法,即让客户端只发送他们想要更改的数据,是每个“db table”类型都有一个额外的“param”类型。因此,例如,给定您的 Notification 类型,您将有一个 NotificationParams 类型,如下所示:

type NotificationParams struct {
    Id      int64 `json:"id"`
    // use pointers so that a field that is not present in the json
    // will result in a nil pointer value, which tells you that no
    // update is needed for that column, it also allows the client
    // to send an empty string if they want to delete the content of
    // some column, e.g. Body.
    Type    *NotificationType
    Subject *string `json:"confidence"`
    Body    *string `json:"body"`
    // and other fields that you want to allow the client change
}

然后在您的处理程序或任何您可以按照以下方式执行操作的地方:

params := &NotificationParams{} // unmarshal from json
notif := &Notification{} // read from db using params.Id

// change only those fields that were provided
if params.Type != nil {
    notif.Type = *params.Type
}
if params.Subject != nil {
    notif.Subject = *params.Subject
}
if params.Body != nil {
    notif.Body = *params.Body
}

// do some validation...

// if ok save notif using mysql UPDATE

更新

如果您想避免编写大量 if 语句,您可以编写几个“setter”或“apply”函数(您更喜欢哪个名称)来为您执行此操作,每种类型一个你想支持的,例如一种用于string,一种用于time.Time,等等。

以这个函数为例:

// The variadic list of functions can be used to transform (think
// sanitization, normalization, etc.) the value before setting
// it to the dst pointer.
func ApplyStr(dst, src *string, fns ...func(string) string) {
    if src != nil {
        s := *src
        for _, fn := range fns {
            s = fn(s)
        }

        *dst = s
    }
}

然后你会使用像this playground example 这样的函数。

【讨论】:

  • 感谢 mkopriva。这会奏效,我走的是同一条路。但是,我正在检查我们是否可以通过 less if else 来实现这一目标。我在需要实现此功能的地方收到了大量的 put 请求。再次感谢您的宝贵时间。
  • @BinishJohn 如果您在解组之前可以访问旧记录,您可以将数据解组到其中。即:第一步从数据库中获取记录;第二步将 json 解组到其中。 json unmarshaler 不会触及 json 中没有对应值的字段,保持旧的字段值不变。如果您需要“保护”某些字段不被更改,您可以将 Notification 嵌入到声明这些字段的结构中,然后解组器将设置这些字段而不是 Notification 本身上的字段。
  • @BinishJohn 在我之前的评论中举例说明了这个概念:play.golang.org/p/erh0y8OmH8
  • 谢谢:)。解决它。我可以扩展它以适应我的服务。非常感谢
【解决方案2】:

以下方法使用GORM库在接收到payload后持久化你的数据:

package main

import (
    "github.com/jinzhu/gorm"
    _ "github.com/jinzhu/gorm/dialects/mysql"
    "time"
)


type NotificationType struct {
    gorm.Model

}

type Notification struct {
    gorm.Model
    Id                 int64     `json:"id"`
    Type               NotificationType
    Subject            string    `json:"confidence"`
    Body               string    `json:"body"`
    CreatedDate        time.Time `json:"created_dt"`
    CreatedBy          int64     `json:"created_by"`
    ParentNotification int64     `json:"parent_id"`
    IsExpired          bool      `json:"expired"`
}

func main() {
    //your handler code to receive and decode payload from client


    //save data to database
    db, err := gorm.Open("mysql", "user:password@/dbname?charset=utf8&parseTime=True&loc=Local")
    if err != nil {
        panic("failed to connect database")
    }
    defer db.Close()

    // Migrate the schema
    db.AutoMigrate(&Notification{})

    // Read
    var Notification notification
    db.First(&notification, 1) // find notification with id 1 , the id from your payload

    // Update the table from notification object
    db.Save(&notification)
}

【讨论】:

    猜你喜欢
    • 2011-01-19
    • 2022-01-11
    • 1970-01-01
    • 1970-01-01
    • 2019-05-16
    • 1970-01-01
    • 2020-04-26
    • 2020-05-14
    • 2011-10-01
    相关资源
    最近更新 更多