How to set column value as false - go

I want to update a column "enabled" to false using Gin framework in Go. I know that it doesn't allow the column to be set as false by default, so I wrote the below code to handle that.
if err := db.Model(&subscription).Update(map[string]interface{}{"enabled": false}).Error; err != nil {//do something}
Somehow, this doesn't seem to be working anymore. What is wrong in this code?
This is my model:
type Subscription struct {
gorm.Model
Enabled bool `gorm:"DEFAULT:True"`
Deleted bool `gorm:"DEFAULT:False"`
UserID uint `gorm:"not null"`
SubscriptionTypeID uint `gorm:"not null"`
Cap int `gorm:"DEFAULT:-1"`
DateOfMonth string `gorm:"DEFAULT:'0'"`
}

You can use the Updates method to do it in the way you have tried. This also works for multiple columns.
if err := db.Model(&subscription).Updates(map[string]interface{}{"enabled": false}).Error; err != nil {//do something}
Also, you can use the Update method to update the single column.
if err := db.Model(&subscription).Update("enabled", false).Error; err != nil {//do something}
Here you can find more variations on how to update a single column or multiple columns.

Ankita Gupta, You should declare you model like this:
type MyModel struct {
gorm.Model
Enabled bool `gorm:"default:false"`
}
In this way the boolean default value is false

Related

How to do a many-to-many query

I'm trying to understand how to use GORM to make query on items with many2many relations but I'm really lost.
I've got the following database model:
type Asset struct {
gorm.Model
Id uint `gorm:"primaryKey"`
MachineUID string `gorm:"type:varchar(128)" json:"machine_uid"`
AssetToken string `gorm:"uniqueIndex;type:varchar(128)"`
CommandQueries []*CommandQuery `gorm:"many2many:command_asset;"`
}
type CommandQuery struct {
gorm.Model
Id uint `gorm:"primaryKey"`
UUID string `gorm:"type:varchar(128)" json:"uuid"`
CmdType int `json:"cmdtype"`
CmdArgs string `gorm:"type:varchar(128)" json:"cmdargs"`
Assets *[]Asset `gorm:"many2many:command_asset;"`
Active bool
}
First, i'm successfully trying to retrieve an asset from a token with something like this:
token := "test-token"
var result Asset
db.Where("asset_token = ?", token).First(&result)
if result.Id == 0 {
return fmt.Errorf("Asset cannot be found in database")
}
But fom this returned struct, i would like to retrive all CommandQuery objects where:
this asset is in CommandQuery.assets
Where CommandQuery.active = true
I tried many things but nothing works, any help would be appreciated.
If I understood correctly, you want to load a slice of CommandQuery objects, and these objects should contain only assets where asset_token should be equal to the token you passed. Also, return only CommanQuery objects that have active=true.
If this is the case, it can be done like this:
token := "test-token"
var list []CommandQuery{}
tx := db.Preload("Assets", func (gdb *gorm.DB) *gorm.DB{
return gdb.Where("asset_token = ?", token)
}).
Where("active = ?", true).Find(&list)
if tx.Error == nil {
return nil, tx.Error
}
return *list, nil
In short, custom preloading is used to load assets into command query objects.

Partial updates of objects

I want to enable update functionality for my User object in my fiber/gorm backend. It works fine when I update all fields together using the Save function. However, when I do not have all fields present in the update request (for example only the Birthday field but not the Phone field) it overwrites the rest of the fields with their respective null values.
func UserUpdateByID(c *fiber.Ctx) error {
db := database.DBConn
// Parse the body to fit user entity
user := entities.User{}
if err := c.BodyParser(&user); err != nil {
return c.Status(500).SendString(err.Error())
}
// Update record
record := db.Save(&user)
if record.Error != nil {
return c.Status(500).SendString(record.Error.Error())
}
return c.JSON(record.Value)
When I change the line with record := db.Save(&user) to
mappedData, _ := StructToMap(user)
record := db.Model(&entities.User{}).Update(mappedData)
I receive the error that Update can not handle map of interfaces: sql: converting argument $10 type: unsupported type map[string]interface {}, a map
Update 1:
The mentioned StructToMap function looks like this:
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
}
Update 2:
The User object looks like:
type User struct {
gorm.Model
Identity string
Birthday time.Time
Phone string
City string
...
ActivityData []Activity
}
Looking, on gorm doc(https://gorm.io/docs/update.html), you can do something like this :
Use the Updates instead of Update.
db.Model(&user).Updates(User{Name: "hello", Age: 18, Active: false})
You can also use a db.Debug, to show the final query that gorm made, and see if matches with what are you expecting.

Gorm query returning only a single row

We're trying to use Gorm with mysql 8 to much frustration.
I have the following tables (simplified for brevity here)
type StoragePool struct {
gorm.Model
PoolId string `json:"id" gorm:"column:poolid;size:40;unique;not null"`
Volumes []Volume `json:"volumes" gorm:"foreignkey:StorageId;association_foreignkey:PoolId"`
}
type Volume struct {
gorm.Model
StorageId string `json:"storageid" gorm:"column:storageid;size:40"`
}
Data insertions seem to work fine. Both tables get populated and no constraints are violated.
A query that expects a single record seems to work fine:
poolRecord := &StoragePool{}
if err := tx.Where("poolid = ?", pool.PoolId).First(&StoragePool{}).Scan(poolRecord).Error; err != nil {
return err
}
This query only returns a single row. When I perform this exact query as raw SQL outside of go, it returns all 31 records I expect.
var poolVolumes []Volume
if err := tx.Where("storageid = ?", pool.PoolId).Find(&Volume{}).Scan(&poolVolumes).Error; err != nil {
return err
}
log.Debugf("found %d volumes belonging to %q [%s]", len(poolVolumes), pool.Name, pool.PoolId)
According to the docs, that second sql statement is the equivalent of "SELECT * FROM VOLUMES WHERE STORAGEID = 'poolid'". That is not the behavior I am getting.
Anyone have any ideas what I'm doing wrong here?
I rarely use an ORM while coding with go, but following the doc from gorm, it seems like you are doing it the wrong way.
Scan is used for scanning result into another struct, like this:
type Result struct {
Name string
Age int
}
var result Result
db.Table("users").Select("name, age").Where("name = ?", 3).Scan(&result)
The correct way to get query results into a slice of structs should be:
var poolVolumes []Volume
if err := tx.Where("storageid = ?", pool.PoolId).Find(&poolVolumes).Error; err != nil {
return err
}

Using struct to update values

I'm stuck when I'm updating an empty string values in a struct for updating dynamodb table.
Currently I have this struct
type Client struct {
ClientID *string `json:"client_key,omitempty"`
Name *string `json:"client_name,omitempty"`
Address *string `json:"address,omitempty"`
Country *string `json:"country,omitempty"`
City *string `json:"city,omitempty"`
State *string `json:"state,omitempty"`
PostCode *string `json:"post_code,omitempty"`
CreatedAt *time.Time `json:"created_at,omitempty"`
}
And this code when updating an item
keyAttr, err := dynamodbattribute.MarshalMap(key)
if err != nil {
return nil, err
}
valAttr, err := dynamodbattribute.MarshalMap(attributes)
if err != nil {
return nil, err
}
keyAttr will be used for the Key field and valAttr will be used in ExpressionAttributeValues field. Note that I didn't include the complete updating fields function to save space. But I will do that if you ask for it.
Currently the function is running fine except when I updated one of the field with empty string. E.g. client.Address = aws.String(""). While I'm fine with dynamodb converting my empty string to null, I can't seem to find a way to update it because of the omitempty tag.
I need the omitempty tag to ignore all nil values. However, I just researched that the omitempty tag also omits empty string values. Currently I have to make a struct in my function like this.
type client struct {
Name *string `json:"client_name"`
Address *string `json:"address"`
Country *string `json:"country"`
City *string `json:"city"`
State *string `json:"state"`
PostCode *string `json:"post_code"`
}
But i'm not a fan of repeating things. So, the question is: is there any better way of doing this? How do you guys use structs with dynamodb?
EDIT
Based on #Peter's comment, it seems that json.Encode() does print the empty string if it's not nil.
{"client_key":"test","username":"test","email":"","first_name":"test","last_name":"","phone":"","title":"","email_verified":false,"phone_verified":false,"updated_at":"2018-12-06T14:04:56.2743841+11:00"}
The problem seems to be in dynamodbattribute.MarshalMap function
After several trials, I finally got it. I didn't test it so I don't know whether it's buggy or not. But it seems to work for me right now.
So what I did was encode the struct with json.Marshal first then use json.Unmarshal with a map[string]interface{}. Then, I use dynamodbattribute.Marshal to convert it to map[string]*AttributeValue
Here's the code:
var temp map[string]interface{}
json.Unmarshal(tempStr, &temp)
valAttr, err := dynamodbattribute.MarshalMap(temp)
if err != nil {
return nil, err
}

Preload can't find field fieldName in *models.Catalog

I can't find an answer to my question. I am using jinzhu/gorm in a golang project:)
I have the following structs:
type Catalog struct {
ID int64 `gorm:"primary_key" form:"id"`
SubDomainID int64 `form:"sub_domain_id"`
ServiceTypeID int64 `form:"service_type_id"`
Checked bool `form:"checked"`
CreatedAt time.Time `form:"created_at"`
UpdatedAt time.Time `form:"updated_at"`
SubDomain SubDomain
}
type SubDomain struct {
Id int64 `gorm:"primary_key" form:"id"`
NameRu string `form:name_ru`
url string `form:url`
}
When I try to get catalog with preloading of subdomain:
var catalog Catalog
fmt.Println(catalog.SubDomain)
err := db.Preload("SubDomain").Where("checked = 0").First(&catalog).Error
if err != nil {
return &catalog, err
}
I get the following error: can't find field SubDomain in *models.Catalog
Why is this happening?
I expect there will be 2 queries:
select * from catalogs where checked = 0;
select * from sub_domains where id = (catalog.sub_domain_id)
I'm still new to gorm, but I think I know your problem and also have a (partial) solution.
As stated before (and you said so yourself), when applying "select * from..." it also looks for the field SubDomain (because it is in your struct).
So I believe this should work:
var catalog Catalog
fmt.Println(catalog.SubDomain)
err := db.Preload("SubDomain").Select("ID","SubDomainID", "ServiceTypeID").Where("checked = 0").First(&catalog).Error
if err != nil {
return &catalog, err
}
note how i specified the exact fields. A better solution will be to write a function to exclude member which are fields, using reflection. I am using a similar solution myself. it kinda looks like this:
for each member of Domain:
if member is string or boolean
fields.append(member).
return db.Select(fields) // actual gormdb's Select

Resources