How to add object to the array in mongodb - 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"`
...
}

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.

Aggregation and filter in Golang in MongoDB

i use https://github.com/Kamva/mgm for my Golang project with MongoDB as database. I´ve been searching a way to aggregate and filter a collection.
Here my working Aggregation of the Author (a user) of a article:
authorCollName := mgm.Coll(&Models.User{}).Name()
articles := []Models.Article{}
err = mgm.Coll(&Models.Article{}).SimpleAggregate(&articles, builder.Lookup(authorCollName, "authorid", "_id", "author"))
But i want filter it on a specific category like here in this simple find:
err = collection.SimpleFind(&articles, bson.D{{"category", objID}})
The Models:
type Article struct {
mgm.DefaultModel `bson:",inline"`
Name string `json:"name" bson:"name"`
AuthorId primitive.ObjectID `json:"authorId" bson:"authorid"`
Author []User `json:"author" form:"author"`
Category primitive.ObjectID `json:"category,omitempty"`
}
type User struct {
mgm.DefaultModel `bson:",inline"`
Forename string `json:"forename"`
Name string `json:"name"`
Email string `json:"email"`
Password string `json:"password"`
}
Can someone give me a hint, how i can solve it that i can use aggregation and a filter together?
The solution:
err = mgm.Coll(&Models.Article{}).SimpleAggregate(&articles, builder.Lookup(authorCollName, "authorid", "_id", "author"), M{operator.Match: M{"category": objID}})

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

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.

How to use Find().Select().One() in go mongo-driver library

This code is working fine in go mgo library
result interface{}
err = getCollection.Find(bson.M{}).Select(bson.M{"_id": 1}).One(&result)
but I want to perform this using go mongo-driver library
I have tried below code but it is not working as the above one
err = getCollection.FindOne(ctx, bson.M{}, options.FindOne().SetProjection(bson.M{"_id": 1})).Decode(&result)
My test collection data is
example{
"_id":ObjectId(),
"Name":"qwert"
}
Anyone suggest me how can we achieve this in mongo-driver?
i can't comment on your question because i am new contributor here, i am using mongo-driver in my project now, i have tried to fetch only projection only some fields to be show up,
can you specific the argument on second for filtering ?
var (
opt options.FindOneOptions
modelStruct model.Person
)
filter := bson.M{"email": "hello#test.com"}
opt.SetProjection(bson.M{"name": 1})
err := collection.findOne(context.Background(), filter, opt).Decode(&modelStruct)
if that doesn't work, then you should limit the struct , make sure in your model.Person has data like this
type Person struct {
Name string `json:"name" bson:"name"`
Gender string `json:"gender" bson:"gender"`
}
or you can just make own model for limit the fields:
var personLimitOnlyGetName struct {
Name string `json:"name" bson:"name"`
}
// please look carefully in your collection field for camelCase
opt.SetProjection(bson.M{"name": 1})

How to update a sub-document array fields along with some other fields in Mongodb, Mgo?

Can we update sub-document array fields along with other document fields in Mgo?
If so, please help me with my query.
c := db.C("user")
colQuerier := bson.M{"email": *olduname}
change := bson.M{"$set":bson.M{"password":*pwd, "place":*place, "emails.$.received":*received,"emails.$.sent":*sent}}
err := c.Update(colQuerier, change)
My Database Structs are as follows:
type Emails struct{
Id bson.ObjectId `bson:"_id,omitempty"`
Received string
Sent string
}
type User struct {
Id bson.ObjectId `bson:"_id,omitempty"`
Email string
Password string
Place string
Emails
}
I am getting a run time error saying: The positional operator did not find the match needed from the query. Unexpanded update: emails.$.received
It should be emails.received as received is not an array, so you don't need the positional operator $:
c := db.C("user")
colQuerier := bson.M{"email": *olduname}
change := bson.M{"$set":bson.M{"password":*pwd, "place":*place, "emails.received":*received}}
err := c.Update(colQuerier, change)