What is the best way to update `HAS ONE` using gorm? - postgresql

I have two models
type User {
ID uint `gorm:"primarykey" json:"-"`
FirstName string `json:"firstName"`
LastName string `json:"lastName"`
Email string `json:"email"`
Profile Profile `gorm:"constraint:OnDelete:CASCADE;"`
}
and
type Profile struct {
ID uint `gorm:"primarykey" json:"-"`
UserID uint `gorm:"uniqueIndex:idx_uniqueProfile" json:"-"`
PhoneNumber string `json:"phoneNumber"`
}
Assuming i have json data to update it like this
data := schema.UserUpdate{
FirstName: "ABC", LastName: "XYZ",
Profile: schema.Profile{PhoneNumber: "123445666"}}
and I update user like this
var user authmodels.User
// get user object to be updated
if err := database.Db.Joins("Profile").First(&user, "uid = ?", uid).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return c.Status(fiber.StatusNotFound).JSON(er.NotFound(""))
}
return c.Status(fiber.StatusBadRequest).JSON(er.BadRequest(err.Error()))
}
// data used to update user object
var updateData = authmodels.User{FirstName: data.FirstName, LastName: data.LastName,
Profile: authmodels.Profile{PhoneNumber: data.Profile.PhoneNumber}}
// update user object and it's profile as well
if err := database.Db.Model(&user).Updates(updateData).Error; err != nil {
return c.Status(fiber.StatusBadRequest).JSON(er.BadRequest(err.Error()))
}
Output results
User Model it only update selected fields (OK)
UPDATE "users" SET "updated_at"='2022-07-07 00:03:18.57',"first_name"='Fiber',"last_name"='Go lang' WHERE "id" = 11
Profile Model it insert instead of updating and it uses original data instead of new data(phoneNumber)
INSERT INTO "profiles" ("created_at","updated_at","user_id","phone_number","id") VALUES ('2022-07-06 23:58:25.61','2022-07-06 23:58:25.61',11,'255765889960',15) ON CONFLICT ("id") DO UPDATE SET "user_id"="excluded"."user_id" RETURNING "id"

You have to set FullSaveAssociations to true if you want to update associations data. Check it out: https://gorm.io/docs/session.html
Therefore your update query shall look like:
err := database.Db.Session(&gorm.Session{FullSaveAssociations: true}).Updates(&updateData).Error
And make sure to specify the User and Profile IDs in updateData or through a WHERE clause.

Related

GORM unable to update data in one to many relationship

I have two tables users and documents. They are related in such a way that each document must belong to a user using a one to many relationship. When I try updating a document I get the following error
ERROR: insert or update on table "documents" violates foreign key
constraint "fk_users_documents" (SQLSTATE 23503)
Here are my structs definition and update function
type User struct {
gorm.Model
Name string
Email string
Password string
Documents []Document
}
type Document struct {
gorm.Model
Name string
UserID uint
}
//Update document by id
func (h handler)UpdateDocument(w http.ResponseWriter, r *http.Request) {
// once again, we will need to parse the path parameters
var updatedDoc Document
reqBody, _ := ioutil.ReadAll(r.Body)
json.Unmarshal(reqBody, &updatedDoc)
var document Document
vars := mux.Vars(r)
id := vars["id"]
if result := Db.First(&updatedDoc, id); result.Error != nil {
fmt.Println(result.Error)
}
document.Name=updatedDoc.Name
Db.Save(&document)
json.NewEncoder(w).Encode(&updatedDoc)
}
You are calling Db.Save(&document) but document has only its Name field populated. This means that the UserID is set to 0. I'm guessing you don't have any user with ID 0 present in the User table, therefore this violates the foreign key constraint.
The UserID field shall always be set to an existing user when updating a document otherwise the query will fail.
Regardless of this, I'd suggest you to study a bit of database and golang basics because the code you posted is quite messy.

Gorm Association Delete does not remove rows, instead update rows

A client has many Roles. I want to delete all Roles once a client is deleted.
type Client struct {
Id string `gorm:"primaryKey"`
CreatedAt time.Time
UpdatedAt time.Time
Roles [] Role
}
type Role struct {
Id uint `gorm:"primarykey"`
CreatedAt time.Time
UpdatedAt time.Time
ClientID string
}
return db.Transaction(func(tx *gorm.DB) error {
err = db.Model(&clientToRemove).Association("Roles").Delete(&clientToRemove.Roles)
if err != nil {
return err
}
err = db.Delete(&clientToRemove).Error
if err != nil {
return err
}
return nil
})
I expect related rows in role to be removed, instead of delete query, it executes an update query to remove client_id.
[210.834ms] [rows:1] UPDATE "role" SET "client_id"=NULL WHERE "role"."client_id" = 'xxxxxxxxxxx' AND "role"."id" = 9
How to completely remove rows in associated role table?
Database is Postgres
As stated in the documentation, the delete with association operation will just remove the references between Client and TenantRole. In your case, it just updated the TenantRole records to set the client_id to NULL.
If you want to delete the objects as well, you can try using Select with the delete operation. Please note that this only works if the primary key is not zero, so your query might look something like this:
err = db.Select("TenantRoles").Delete(&Client{Id: clientId}).Error
or just use clientToRemove if it already has the Id field populated
err = db.Select("TenantRoles").Delete(&clientToRemove).Error

GORM Error on insert or update on table violates foreign key constraint

I have the following set of GORM models, with 2 orders of one-to-many relations:
type Order struct {
ID string `gorm:"column:id"`
ClientID string `gorm:"primaryKey;column:client_id"`
Name string `gorm:"column:name"`
Albums []Album `gorm:"foreignKey:RequestClientID"`
}
type Album struct {
AlbumID string `gorm:"primaryKey;column:album_id"`
RequestClientID string `gorm:"foreignKey:ClientID;column:request_client_id"`
Pictures []Picture `gorm:"foreignKey:AlbumID"`
}
type Picture struct {
PictureID string `gorm:"primaryKey;column:picture_id"`
AlbumID string `gorm:"foreignKey:AlbumID;column:album_id"`
Description string `gorm:"column:description"`
}
When I attempt to insert data as follows, I get the error pq: insert or update on table "albums" violates foreign key constraint "fk_orders_albums".
test := Order{
ID: "abc",
ClientID: "client1",
Name: "Roy",
Albums: []Album{
{
AlbumID: "al_1",
Pictures: []Picture{
{
PictureID: "pic_1",
Description: "test pic",
},
},
},
},
}
gormDB.Save(&test)
I followed the solution on this similar question, but can't seem to get it to work: Golang: Gorm Error on insert or update on table violates foreign key contraint
Based on your entity model, Your schema would be like this:
Orders table is parent table, didn't depend to any table
Albums table has foreign key request_client_id which refer to orders table column client_id
Picture table has foreign key album_id which is refer to albums table column album_id
Based on my exploration in gorm documentation here, object in struct will be examine as first association. so, your struct will execute insert to albums first which it violate foreign key schema (expect: insert to orders table should be executed before albums).
But if you want to force using your schema, you can use gorm Association feature.
Here is the idea of using Association:
Expected Query in high level:
Insert to orders table
Insert to albums table
Insert to pictures table
Association Ideas:
Let Albums field value in Orders struct empty
Append Association Albums to Orders model
Since there have another association in Albums, use configuration FullSaveAssociation
Here is the following code:
picture := []Picture{
{
PictureID: "pic_1",
Description: "test pic",
},
}
albums := []Album{
{
ID: "al_1",
Pictures: picture,
RequestClientID: "",
},
}
orders := Order{
ID: "abc",
ClientID: "client1",
Name: "Roy",
}
if err := gormDB.Save(orders).Error; err != nil {
return
}
if err := gormDB.Session(&gorm.Session{FullSaveAssociations: true}).Model(&orders).Association("Albums").Append(albums); err != nil {
return
}
Full code could be found here:
Came across the solution I was looking for while looking into the great answer #giyuu provided. Since I had not saved the item before, I needed to use GORM's Create method:
err = gormDB.Create(&test).Error
Then, when I want to perform an update on any of these values, I use the Save method, with FullSaveAssociations enabled:
err = gormDB.Session(&gorm.Session{FullSaveAssociations: true}).Save(&test).Error

How to add object to the array in mongodb

type Student struct {
ID primitive.ObjectID `bson:"_id,omitempty"`
...
Users []primitive.ObjectID `json:"users"`
...
}
I have this struct and I want to add to Users array. I'm doing this and I'm using Mongo-go-driver
// Filter for search
filter := bson.M{"_id": userID}
// Fields to update
update := bson.M{"$addToSet": bson.M{"users": ID}}
// Update the document
UsersCollection := GetUsersCollection()
UsersCollection.FindOneAndUpdate(context.Background(), filter, update, nil)
Can somebody tell me what I'm doing wrong? It's not adding to the database it's staying null.
Change suggestions:
Change structure metadata tag json to bson
type Student struct {
ID primitive.ObjectID `bson:"_id,omitempty"`
...
Users []primitive.ObjectID `bson:"users"`
...
}

ObjectID automatically set to "0...0" in go with official mongoDB driver

I'm trying to save user entries in a MongoDB database with Go. Users should get an ID automatically. I'm using the offical MongoDB Go driver.
My sources were especially https://vkt.sh/go-mongodb-driver-cookbook/ and https://www.mongodb.com/blog/post/mongodb-go-driver-tutorial.
Struct looks like this:
type User struct {
ID primitive.ObjectID `json:"_id" bson:"_id"`
Fname string `json:"fname" bson:"fname"`
Lname string `json:"lname" bson:"lname"`
Mail string `json:"mail" bson:"mail"`
Password string `json:"password" bson:"password"`
Street string `json:"street" bson:"street"`
Zip string `json:"zip" bson:"zip"`
City string `json:"city" bson:"city"`
Country string `json:"country" bson:"country"`
}
Setting up the database (connection works) and signing up users (based on an HTTP-Request r with a user in it's body):
ctx := context.Background()
uriDB := "someURI"
clientOptions := options.Client().ApplyURI(uriDB)
client, err := mongo.Connect(ctx, clientOptions)
collection := client.Database("guDB").Collection("users")
...
var user User
err := json.NewDecoder(r.Body).Decode(&user)
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
result, err := collection.InsertOne(ctx, user)
...
When I enter the first user, it is added to the collection, but the ID looks like this:
_id:ObjectID(000000000000000000000000)
If I now want to enter another user, I get the following error:
multiple write errors: [{write errors: [{E11000 duplicate key error collection: guDB.users index: _id_ dup key: { : ObjectId('000000000000000000000000') }}]}, {<nil>}]
So it seems like again ObjectID 000000000000000000000000 is assigned.
I expected the ID to be automatically set to a unique value for each entry.
Do I have to manually set the ID or how can I assign unique IDs to users?
Per the documentation you linked, you must set the object ID yourself when using structs:
_, err := col.InsertOne(ctx, &Post{
ID: primitive.NewObjectID(), // <-- this line right here
Title: "post",
Tags: []string{"mongodb"},
Body: `blog post`,
CreatedAt: time.Now(),
})
The examples before that using bson.M don't need to specify an ID because they don't send the _id field at all; with a struct, the field is being sent with its zero value (as you've seen).
If you set a document _id, mongodb will use that _id for the document during insertion and will not generate. You have to either omit it, or set it manually with primitive.NewObjectID().