Description

I defined a model which has a column using the tag serializer:json. The Create runs OK. but there is an error sql: converting argument $1 type: unsupported type map[string]interface {}, a map when called Updates.

Does the Updates not support the tag? Or is it used incorrectly?

The code is as below:

package main

import (
    "context"
    "database/sql"
    "fmt"
    "gorm.io/driver/sqlite"
    "gorm.io/gorm"
    "gorm.io/gorm/logger"
    "io"
    "log"
)

type Product struct {
    gorm.Model
    Name    string                 `gorm:"size:64;not null"`
    Price   int                    `gorm:"not null;column:pid"`
    Metrics map[string]interface{} `gorm:"not null;serializer:json;default:'';type:mediumtext"` // json
}

func (p Product) UpdateFields() map[string]interface{} {
    return map[string]interface{}{
        "Name":    p.Name,
        "Price":   p.Price,
        "Metrics": p.Metrics,
    }
}

func main() {
    newLogger := logger.New(
        log.New(os.Stdout, "\r\n", log.LstdFlags),
        logger.Config{
            SlowThreshold:             time.Second,
            LogLevel:                  logger.Info,
            IgnoreRecordNotFoundError: true,
            Colorful:                  true,
        },
    )
    db, err := gorm.Open(sqlite.Open("test.db"), &gorm.Config{
        DryRun: false,
        Logger: newLogger,
    })
    if err != nil {
        panic("failed to connect database")
    }

    db.AutoMigrate(&Product{})

    var p1 Product
    p1.Name = "p1"
    p1.Price = 100
    p1.Metrics = map[string]interface{}{
        "k100": 1.06316447669858,
    }
    rs := db.Create(&p1)
    // rs.Error is nil
    fmt.Println(rs.Error, rs.RowsAffected, p1.ID)

    var p2 Product
    p2.ID = p1.ID
    p2.Name = "p2"
    p2.Price = 200
    p2.Metrics = map[string]interface{}{
        "k1": 1.06,
        "k2": 2.01,
    }

    rs = db.Model(&p2).Updates(p2.UpdateFields())
    // rs.Error is 'sql: converting argument $1 type: unsupported type map[string]interface {}, a map'
    fmt.Println(rs.Error, rs.RowsAffected)
}

Comment From: github-actions[bot]

The issue has been automatically marked as stale as it missing playground pull request link, which is important to help others understand your issue effectively and make sure the issue hasn't been fixed on latest master, checkout https://github.com/go-gorm/playground for details. it will be closed in 30 days if no further activity occurs. if you are asking question, please use the Question template, most likely your question already answered https://github.com/go-gorm/gorm/issues or described in the document https://gorm.io ✨ Search Before Asking

Comment From: a631807682

func (p Product) UpdateFields() map[string]interface{} {
    return map[string]interface{}{
        "Name":    p.Name,
        "Price":   p.Price,
        "Metrics": p.Metrics,
    }
}
...
rs = db.Model(&p2).Updates(p2.UpdateFields())

UpdateFields return map[string]interface{}, nothing to do with serializer.

Comment From: BabySid

Thanks for reply. @a631807682 how do I use the Updates api if I want to update multiple columns that contain a serialized tag?

Comment From: a631807682

Thanks for reply. @a631807682 how do I use the Updates api if I want to update multiple columns that contain a serialized tag?

Updates with Struct https://gorm.io/docs/update.html#Update-Selected-Fields

Comment From: BabySid

Thanks for reply. @a631807682 how do I use the Updates api if I want to update multiple columns that contain a serialized tag?

Updates with Struct https://gorm.io/docs/update.html#Update-Selected-Fields

Thanks very much:)

Comment From: zchenyu

Thanks for the workaround. Would it possible to fix updating a map[string]string specified inside a map[string]interface{} ?

Comment From: apuatcfbd

Thanks for reply. @a631807682 how do I use the Updates api if I want to update multiple columns that contain a serialized tag?

Updates with Struct https://gorm.io/docs/update.html#Update-Selected-Fields

Hi, this has limitations, like updating with zero value not working. In my case a field is map[string]string & this sometimes needs to be nil. In these circumstances, we need to update using a map (map[string]interface{}) & that is not working as @zchenyu mentioned above. What to do in this case?

Here's my model

type Price struct {
    BaseModel // id, created/updated columns
    Active                 bool                     `json:"active" gorm:"not null;"`
    Description            string                   `json:"description" gorm:"type:varchar(255);"`
    Metadata               map[string]string        `json:"metadata" gorm:"type:text(1000);serializer:json;"`
}

Here's the updating code

m := new(model.Price)
if tx := database.DB.Preload("Product", func(tx *gorm.DB) *gorm.DB {
    return tx.Select("id", "name", "active")
}).First(m, d.Id); tx.Error != nil {
    return nil, errs.NewSvcErr(errs.ErNotFound, "Price not found", tx.Error)
}

data := map[string]interface{}{
    "Active":      d.Active,
    "Description": d.Description,
    "Metadata":    d.Metadata,
}
if d.Metadata == nil { // doing this as map[string]string(nil) also throws error
    data["Metadata"] = nil
}

// save to db
tx := database.DB.Model(m).Updates(data)
if tx.Error != nil {
    fmt.Printf("xxxx %#v -- %#v \n", tx.Error, data)
    return nil, tx.Error
}

Got the following error (sql: converting argument $3 type: unsupported type map[string]string, a map)

xxxx &fmt.wrapError{msg:"sql: converting argument $3 type: unsupported type map[string]string, a map", err:(*errors.errorString)(0xc0001cf310)} -- map[string]interface {}{"Active":true, "Description":"The description text", "Metadata":map[string]string{"ab":"cd"}, "UpdatedAt":time.Date(2024, time.October, 1, 12, 15, 26, 416531134, time.Local)}

*d is the Dto, content of it is in the log.