Below is my Advertiser Model -
type Advertiser struct {
ID int `json:"id" db:"id"`
CreatedAt time.Time `json:"created_at" db:"created_at"`
UpdatedAt time.Time `json:"updated_at" db:"updated_at"`
Name string `json:"name" db:"name"`
Email string `json:"email" db:"email"`
ContactNumber string `json:"contact_number" db:"contact_number"`
}
I have generated the Advertiser Resource and by default, it had brought-in the actions.
Now, in AdvertiserList action, I need all these fields to do some or the other calculation. But, finally, I would like to only respond with Name, Email and ContactNumber fields.
Remember, this is a List action, which means, we have an array of Advertiser.
Right now, my action does below-
func (v AdvertisersResource) List(c buffalo.Context) error {
tx, ok := c.Value("tx").(*pop.Connection)
if !ok {
return errors.WithStack(errors.New("no transaction found"))
}
advertisers := &models.Advertisers{}
q := tx.PaginateFromParams(c.Params())
if err := q.All(advertisers); err != nil {
return errors.WithStack(err)
}
c.Set("pagination", q.Paginator)
return c.Render(200, r.JSON(advertisers))
}
I'm not sure if I understood your question correctly. However when marshaling to json if you have fields with tags json:"-" then that value is not returned.
Related
I am developing an application that manages quotes using go and gorm. Users create quote, quotes have multiple tags, and users can add quotes to their favorites.
I want to get a list of quotes that a user has added to their favorites. And at that time, I want to get the tag attached to the quotes.
Here is my data models.
type Quote struct {
ID int `gorm:"primary_key" json:"id"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
Text string `json:"text"`
Page int `json:"page"`
Published bool `gorm:"default:false" json:"published"`
Tags []Tag `gorm:"many2many:quotes_tags;" json:"tags"`
User User `json:"user"`
UserID string `json:"user_id"`
FavoriteUsers []User `gorm:"many2many:users_quotes;" json:"favorite_users"`
}
type User struct {
ID string `json:"id"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
Username string `json:"username"`
Quotes []Quote `json:"quotes"`
FavoriteQuotes []Quote `gorm:"many2many:users_quotes;" json:"favorite_quotes"`
}
type Tag struct {
ID int `gorm:"primary_key" json:"id"`
CreatedAt time.Time `json:"created_at"`
Name string `json:"name"`
}
I tried the following and got the favorite quote, but the tags was null. Is there a way to do this with gorm? Thank you in advance.
func (service *Service) GetUser(uid string) (models.User, error) {
fmt.Println(uid)
user := models.User{}
if result := service.db.Preload(clause.Associations).First(&user, "id = ?", uid); result.Error != nil {
return models.User{}, result.Error
}
return user, nil
}
func (service *Service) GetFavoriteQuotes(uid string) ([]models.Quote, error) {
user, err := service.GetUser(uid)
if err != nil {
return []models.Quote{}, err
}
return user.FavoriteQuotes, nil
}
If you check the Preload All documentation, it says:
clause.Associations won’t preload nested associations, but you can use it with Nested Preloading
In your case, this would be something like this:
if result := service.db.Preload("FavoriteQuotes.Tags").Preload(clause.Associations).First(&user, "id = ?", uid); result.Error != nil {
return models.User{}, result.Error
}
I was trying to make a rest API for user registration and on that api there is a field named "gender", so I'm receiving that field as Struct but on user table there is no field for "gender". Is it possible to skip that "gender" field from struct while inserting with gorm?
This is my DataModel
package DataModels
type User struct {
Id uint `json:"id"`
Otp int `json:"otp"`
UserId string `json:"user_id"`
UserType string `json:"user_type"`
FullName string `json:"full_name"`
MobileNo string `json:"mobile"`
Email string `json:"email"`
Gender string `json:"gender"` // I want to skip this filed while inserting to users table
Password string `json:"password"`
}
func (b *User) TableName() string {
return "users"
}
This my Controller Function
func CreateUser(c *gin.Context) {
var user Models.User
_ = c.BindJSON(&user)
err := Models.CreateUser(&user) // want to skip that gender filed while inserting
if err != nil {
fmt.Println(err.Error())
c.AbortWithStatus(http.StatusNotFound)
} else {
c.JSON(http.StatusOK, user)
}
}
This is my model function for inserting
func CreateUser(user *User) (err error) {
if err = Config.DB.Create(user).Error; err != nil {
return err
}
return nil
}
GORM allows you to ignore the field with tag, use gorm:"-" to ignore the field
type User struct {
...
Gender string `json:"gender" gorm:"-"` // ignore this field when write and read
}
Offical doc details about Field-Level Permission
Eklavyas Answer is omitting gender always, not just on Create.
If I am correct you want to Skip the Gender field within the Registration. You can use Omit for that.
db.Omit("Gender").Create(&user)
I am learning golang with gqlgen and gorm as orm, I am creating an app using with 2 models user and messages where the user has a list of messages,
and the messages have sender and recipient.
I have made them like the following
type User struct {
ID string `json:"id" gorm:"primary_key;type:uuid;default:uuid_generate_v4()"`
Username string `json:"username"`
Email string `json:"email"`
FirstName string `json:"firstName"`
LastName string `json:"lastName"`
Messages []*Message `json:"messages"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
DeletedAt *time.Time `json:"deleted_at" sql:"index"`
}
type Message struct {
ID string `json:"id" gorm:"primary_key;type:serial"`
Title string `json:"title"`
Body string `json:"body"`
DueDate time.Time `json:"dueDate"`
IsViewed bool `json:"isViewed" gorm:"default:false"`
SenderID string `json:"senderId" gorm:"type:uuid"`
Sender *User `json:"sender" gorm:"foreignkey:SenderID"`
RecipientID string `json:"recipientId" gorm:"type:uuid"`
Recipient *User `json:"recipient" gorm:"foreignkey:RecipientID"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
DeletedAt *time.Time `json:"deleted_at" sql:"index"`
}
when I retrieve the messages data using Preload
var messages []*models.Message
err := db.
Preload("Sender").
Preload("Recipient").
Find(&messages).Error
if err != nil {
return nil, err
}
return messages, err
it works perfectly but my problem is when trying to retrieve the user with the messages preloaded.
var users []*models.User
err := db.
Preload("Messages").
Find(&users).Error
if err != nil {
return nil, err
}
return users, err
this one gives me the following error can't preload field Messages for models.User
I know I might design my schema wrong if there's a better way to organize it I would appreciate it so much, thanks in advance.
I think you should separate messages in User to SentMessages and ReceivedMessages. Then you can specify foreign keys in User like that:
SentMessages []*Message `gorm:"foreignkey:SenderID" json:"sentMessages"`
ReceivedMessages []*Message `gorm:"foreignkey:RecipientID" json:"receivedMessages"`
then use it as the following:
var users []*models.User
err := db.
Preload("SentMessages").
Preload("ReceivedMessages").
Find(&users).Error
if err != nil {
return nil, err
}
return users, err
that should work as you want
I think you've to take a closer look on how the association are made(actually create from the official gorm package) like (&Model{}).Create(target).Association("Column").Append(&related_instance)
So when you'll retry it using Preload everything gone be Ok. And BTW it work with your current design. Hope it helps.
I'm trying to set up an association between Users and PredictionsBags. My problem is that everything works OK if I use GORM's assumed names for referring objects, but I'd like to change the names a bit.
type User struct {
gorm.Model
// We’ll try not using usernames for now
Email string `gorm:"not null;unique_index"`
Password string `gorm:"-"`
PasswordHash string `gorm:"not null"`
Remember string `gorm:"-"` // A user’s remember token.
RememberHash string `gorm:"not null;unique_index"`
Bags []PredictionsBag
}
Every user, of course, owns zero or more PredictionsBags:
type PredictionsBag struct {
gorm.Model
UserID uint // I want this to be "OwnerID"
Title string
NotesPublic string `gorm:"not null"` // Markdown field. May be published.
NotesPrivate string `gorm:"not null"` // Markdown field. Only for (private) viewing and export.
Predictions []Prediction
}
And I'd like to have .Related() work in the usual way:
func (ug *userGorm) ByEmail(email string) (*User, error) {
var ret User
matchingEmail := ug.db.Where("email = ?", email)
err := first(matchingEmail, &ret)
if err != nil {
return nil, err
}
var bags []PredictionsBag
if err := ug.db.Model(&ret).Related(&bags).Error; err != nil {
return nil, err
}
ret.Bags = bags
return &ret, nil
}
My problem is that I can't find a way to change PredictionsBag.UserID to anything else and still have GORM figure out the relationships involved. I've been reading http://gorm.io/docs/has_many.html#Foreign-Key and if I change the relevant lines to
type User struct {
// …
Bags []PredictionsBag `gorm:"foreignkey:OwnerID"`
}
and
type PredictionsBag struct {
// …
OwnerID uint
// …
}
I get this error:
[2019-07-28 14:23:49] invalid association []
What am I doing wrong? I've also been reading http://gorm.io/docs/belongs_to.html, but I'm not sure which page to follow more closely.
I'll have to Check Related() when I get home, but I think what you're looking for is Preload() This is my example that works with what you want.
package main
import (
"errors"
"fmt"
_ "github.com/go-sql-driver/mysql"
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/mysql"
"log"
)
var DB *gorm.DB
func init() {
var err error
DB, err = gorm.Open("mysql", fmt.Sprintf("%s:%s#tcp(%s:3306)/%s?&parseTime=True&loc=Local", "root", "root", "localhost", "testing"))
if err != nil {
log.Fatal(err)
}
DB.DropTableIfExists(&User{}, &PredictionsBag{})
DB.AutoMigrate(&User{}, &PredictionsBag{})
user := User{Email:"dave#example.com"}
user.Bags = append(user.Bags, PredictionsBag{OwnerID: user.ID, NotesPrivate: "1", NotesPublic: "1"})
DB.Create(&user)
}
func main() {
user := User{Email:"dave#example.com"}
err := user.ByEmail()
if err != nil {
log.Println(err)
}
fmt.Println(user.ID, user.Email, "Bags:", len(user.Bags))
DB.Close()
}
type User struct {
gorm.Model
// We’ll try not using usernames for now
Email string `gorm:"not null;unique_index"`
Password string `gorm:"-"`
PasswordHash string `gorm:"not null"`
Remember string `gorm:"-"` // A user’s remember token.
RememberHash string `gorm:"not null;unique_index"`
Bags []PredictionsBag `gorm:"foreignkey:OwnerID"`
}
type PredictionsBag struct {
gorm.Model
OwnerID uint
Title string
NotesPublic string `gorm:"not null"` // Markdown field. May be published.
NotesPrivate string `gorm:"not null"` // Markdown field. Only for (private) viewing and export.
}
func (ug *User) ByEmail() error {
DB.Where("email = ?", ug.Email).Preload("Bags").Limit(1).Find(&ug)
if ug.ID == 0 {
return errors.New("no user found")
}
return nil
}
Using this might work with related, but I'm not sure what else needs to be changed:
Bags []PredictionsBag `gorm:"foreignkey:OwnerID;association_foreignkey:ID"`
Update:
I can get the Related() method to work, if you state the ForeignKey like the following:
DB.Where("email = ?", ug.Email).Limit(1).Find(&ug)
if ug.ID == 0 {
return errors.New("no user found")
}
if err := DB.Model(&ug).Related(&ug.Bags, "owner_id").Error; err != nil {
return err
}
I'm trying to write an API that will do different things with the data depending on its purpose.
API results - The API should expose certain fields to the user
Validation - Validation should handle different schemas e.g. login form doesn't require Name, but register does
Database - The database should save everything, including password etc. - if I try using the same struct for the API and DB with json:"-" or un-exporting the field the database save also ignores the field
Some sample code is below with a couple of comments in capitals to show where I ideally need to type cast to change the data. As they are different structs, they cannot be type cast, so I get an error. How can I fix this?
Alternatively, what is a better way of doing different things with the data without having lots of similar structs?
// IDValidation for uuids
type IDValidation struct {
ID string `json:"id" validate:"required,uuid"`
}
// RegisterValidation for register form
type RegisterValidation struct {
Name string `json:"name" validate:"required"`
Email string `json:"email" validate:"required,email"`
Password string `json:"password" validate:"required,min=8"`
}
// UserModel to save in DB
type UserModel struct {
ID string `json:"id,omitempty"`
Name string `json:"name"`
Email string `json:"email"`
Password string `json:"password,omitempty"`
Active bool `json:"active,omitempty"`
CreatedAt int64 `json:"created_at,omitempty"`
UpdatedAt int64 `json:"updated_at,omitempty"`
jwt.StandardClaims
}
// UserAPI data to display to user
type UserAPI struct {
ID string `json:"id,omitempty"`
Name string `json:"name"`
Email string `json:"email"`
Active bool `json:"active,omitempty"`
}
// register a user
func register(c echo.Context) error {
u := new(UserModel)
if err := c.Bind(u); err != nil {
return err
}
// NEED TO CAST TO RegisterValidation HERE?
if err := c.Validate(u); err != nil {
return err
}
token, err := u.Register()
if err != nil {
return err
}
return c.JSON(http.StatusOK, lib.JSON{"token": token})
}
// retrieve a user
func retrieve(c echo.Context) error {
u := IDValidation{
ID: c.Param("id"),
}
if err := c.Validate(u); err != nil {
return echo.NewHTTPError(http.StatusBadRequest, err.Error())
}
// NEED TO CAST USER TO UserAPI?
user, err := userModel.GetByID(u.ID)
if err != nil {
return err
}
return c.JSON(200, lib.JSON{"message": "User found", "user": user})
}