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.