Update method does not update zero value

5.5k Views Asked by At

Original Question

When using the Update method in GORM the new data does not get saved. i.e. I want to set a bool from true to false, but it stays true even after the Update method.

In the description of the method there is a warning: "WARNING when update with struct, GORM will not update fields that with zero value"

Since I am using a struct to update and false is the zero value of bool, this seems expected behaviour, but I don't see any reason why to do so and how to overcome this.

func UpdateData(c *fiber.Ctx) error {
    db := database.DBConn

    data := new([]entities.Data)

    if err := c.BodyParser(&data); err != nil {
        return err
    }

    db.Update(&data)
    return c.JSON(data)
}

Solution Summary

First, as suggested I left out the new keyword when instantiating the structs. Then, I used a helper function (from here) for converting a struct to map while keeping the json alias as keys:

// StructToMap Converts a struct to a map while maintaining the json alias as keys
func StructToMap(obj interface{}) (newMap map[string]interface{}, err error) {
    data, err := json.Marshal(obj)

    if err != nil {
        return
    }

    err = json.Unmarshal(data, &newMap) // Convert to a map
    return
}

Then I loop over each element in the data slice in order to convert it and update it one by one:

func UpdateData(c *fiber.Ctx) error {
    db := database.DBConn

    data := []entities.Dard{}

    if err := c.BodyParser(&data); err != nil {
        return err
    }

    for _, record := range data {
        mappedData, _ := StructToMap(record)
        db.Model(&entities.Data{}).Update(mappedData)
    }

    return c.JSON(data)
}

*Error handling is obviously reduced in this example.

2

There are 2 best solutions below

2
On BEST ANSWER

From official doc

NOTE When update with struct, GORM will only update non-zero fields, you might want to use map to update attributes or use Select to specify fields to update

So use map[string]interface{} to update non-zero fields also. Example:

db.Model(&user).Updates(map[string]interface{}{"name": "hello", "age": 18, "actived": false})

As you have struct already you can convert struct into map[string]interface{} (See details about conversion) then update. Another way is change the type of field as pointer.

0
On

As for me, all fields must be saved by default, also with empty values (because, how to delete an field value from the model instance?).

Actual documentation has an example, how to enable all fields for update (regarding the field permissions, e.g. it will not update createonly fields).

// Select all fields (select all fields include zero value fields)
db.Moodel(&user).Select("*").Updates(User{Name: "jinzhu", Role: "admin", Age: 0})