How to update more than one MongoDB field - mongodb

I am so frustrated with the Official MongoDB for Go. There is really no documentation. I am trying to update more than one field in a collection. All references, as normal are the simplest and updating one field:
update := bson.D{bson.E{"$set", bson.E{"releaseimage", r.ReleaseImage}}}
That works. I have tried various ways to expand that to set two fields and get errors:
update := bson.D{
{"$set",
bson.E{"releaseimage", r.ReleaseImage},
//bson.E{"releasepath", r.ReleasePath},
},
// {"$set",
// bson.E{
// "releasepath", r.ReleasePath}},
}
the first one remove the comments in the first set. invalid syntax for second attempt remove the comments on the second set. invalid syntax.
I am at a loss. To keep going I am doing two updates, one right after another. Inefficient.
Thank you.

For multiple fields, you have to create an array of bson element(bson.E). then append/assign as many fields you want in array item.
var update []bson.E
if r.ReleaseImage != "" {
update = append(update, bson.E{"releaseimage", r.ReleaseImage})
}
if r.Releasepath != "" {
update = append(update, bson.E{"releasepath", r.Releasepath})
}
// now update db
result, err := coll.UpdateOne(
context.Background(),
bson.D{
{"id", r.ID},
},
bson.D{
{"$set", update},
{"$currentDate", bson.D{
{"updated", true},
}},
},
)
Hope this helps

Simply do like this:
uQuery := make(bson.M)
if len(r.ReleaseImage)>0{
uQuery["releaseimage"]=r.ReleaseImage
}
if len(r.Releasepath)>0{
uQuery["releasepath"]=r.Releasepath
}
updateQ := make(bson.M)
updateQ["$set"] = uQuery
Now simply pass 'updateQ' to mongodb update Wrapper function along with findQuery.

Related

Using multiple arrayFilters on the same top-level field in MongoDB with Go

I'm trying to update a nested document in MongoDB based on certain conditions. The problem is that using arrayFilters on the same top-level field name is not allowed. Any solutions for solving this problem?
Error: Found multiple array filters with the same top-level field name x
filter := bson.D{primitive.E{Key: "_id", Value: e.EventId}}
arrayFilters := options.ArrayFilters{
Filters: []interface{}{
bson.M{"x._id": tt.TypeId},
bson.M{"x.typeAmountUsed": bson.M{"$lt": "$x.typeAmount"}}, // <-- multiple filters
},
}
upsert := true
opts := options.UpdateOptions{
ArrayFilters: &arrayFilters,
Upsert: &upsert,
}
update := bson.M{
"$inc": bson.D{{"eventTicketTypes.$[x].typeAmountUsed", 1}},
}
if _, err = events.UpdateOne(sessCtx, filter, update, &opts); err != nil {
return nil, err
}
To use multiple criteria in the same filter, combine them into a single filter.
See https://www.mongodb.com/docs/manual/reference/method/db.collection.update/#specify-arrayfilters-for-array-update-operations
However, arrayFilters do not support directly comparing 2 fields within the array element. You might be able to accomplish that with $map.

Insert value as soon as field updated

I have a basic document versioning system. While updating a record, I should save the current field value in another field(as a list/array, so we going to use $push in MongoDB).
For example, if I want to update the user_name field, the current name should be saved to old_user_names
sample code
func UpdateDocument(ctx context.Context, id uuid.UUID, obj interface{}) error {
filter := bson.M{"_id": id}
update := bson.M{"$set": obj,
"$push": bson.D{
{"old_original_names", "old_original_name_here"},
},
"$inc": bson.M{"version": 1}}
r.db.FindOneAndUpdate(ctx, filter, update)
return nil
}
I should add the current object's name field to "current_name_here" but I couldn't figured it out.

Add Fields to MongoDB Inner Object

I'm trying to append fields to an object in my mongodb collection. So far this is what my document in MongoDB looks like.
My users can have multiple devices so I'm trying to append more fields to the devices object. I have tried to use $push for an array instead of an object but I didn't like how I would have to access the data later on when I retrieve it from the database.
So I started to use $set. $set works great because it gives me the format in which I want my data to save in the db but it will continually override my one key value pair in the devices object every time and I don't want that to happen.
db.go
func AddDeviceToProfile(uid string, deviceId int, deviceName string) {
client := ConnectClient()
col := client.Database(uid).Collection("User")
idString := strconv.Itoa(deviceId)
filter := bson.M{"uid": uid}
update := bson.M{
"$set": bson.M{"devices": bson.M{idString: deviceName}}, <------ Need to fix this
}
option := options.FindOneAndUpdate()
_ = col.FindOneAndUpdate(context.TODO(), filter, update, option)
log.Print("Device Added")
_ = client.Disconnect(context.TODO())
}
I have looked into using $addFields but I don't know if I was doing it correctly I just replaced $set above and added $addFields and I also tried it this way
update := bson.M{
"devices": bson.M{"$addFields": bson.M{idString: deviceName}},
}
What I want my document to look like
Instead of using $push or $addFields what you need is $set directive.
To specify a field in an embedded document, use dot notation.
For the document matching the criteria _id equal to 100, the following operation updates the make field in the devices document:
db.products.update(
{ _id: 100 },
{ $set: { "devices.make": "zzz" } }
)
Converting them to Go syntax is easy as well. What you are doing is correct. The following should work or might require a little bit of tweaking.
func AddDeviceToProfile(uid string, deviceId int, deviceName string) {
client := ConnectClient()
col := client.Database(uid).Collection("User")
idString := strconv.Itoa(deviceId)
filter := bson.M{"uid": uid}
update := bson.M{"$set": bson.M{"devices." + idString: deviceName}}
option := options.FindOneAndUpdate()
_ = col.FindOneAndUpdate(context.TODO(), filter, update, option)
log.Print("Device Added")
_ = client.Disconnect(context.TODO())
}

UpdateOne, ReplaceOne, FindOneAndReplace - patternmatch, but no upd data

I'm Using Mongo Go Adapter: github.com/mongodb/mongo-go-driver/
I'm trying different patterns but none of them working for me.
//ref struct
type userbase struct {
Name string `bosn:"Name"`
Coins int `bson:"Coins"`
}
//ref code, it's updating _id, but not updating a value
filter := bson.M{"name": "Dinamis"}
update := bson.D{{"$inc", bson.M{"Coins": 1}}}
db := Client.Database("Nothing").Collection("dataUser")
db.UpdateOne(context.Background(), filter, update)
//update filters that i also used
update := bson.D{{"$inc", bson.D{{"Coins", 1},}},}
//simple ways was tryed also
update := &userbase{name, amount} //should i try *userbase{} ?
//Also i'm tryed
ReplaceOne()
FindOneAndReplace()
FindOneAndUpdate()
it's hard to dig deeper b-cuz of luck of actual documentation: https://docs.mongodb.com/ecosystem/drivers/go/
Thanks #Wan Bachtiar for answering this in official MongoDB-go-adapter group.
By default queries in MongoDB is case sensitive on the field name. In
your struct you defined the field to be Name, but in your filter to
specify name. This would result in no documents matching the query
predicates for the the update operation. For example, if you have a
document as below:
{ "_id": ObjectId("..."), "Name": "Dinamis", "Coins": 1 }
You can perform an update to increment the number of Coins using below
snippet:
collection := client.Database("Nothing").Collection("dataUser")
filter := bson.M{"Name": "Dinamis"}
update := bson.D{{"$inc", bson.M{"Coins": 1}}}
result, err := collection.UpdateOne(context.TODO(), filter, update)
Also, note that you have a typo on the bson tag in your struct. It’s
supposed to be bson:"Name" not bosn:"Name". You may find Query
Documents as a useful reference (Select the Go tab to show examples in
Go)
Regards, Wan.

Update/Replace mongodb document using struct & mongodb/mongo-go-driver

I am trying to update/replace a mongodb document using a struct but i keep on getting err: update document must contain key beginning with '$'
collection := r.client.Database(database).Collection(greetingCollection)
payment.MongoID = objectid.New()
filter := bson.NewDocument(bson.EC.String("id", payment.ID))
_, err := collection.UpdateOne(ctx, filter, payment)
return err
I believe the accepted answer did not work for me because I am using the go.mongodb.org/mongo-driver package. With this package, the syntax is even simpler:
update := bson.M{
"$set": yourDocument,
}
collection.UpdateOne(ctx, filter, update)
You should provide an update statement instead of a document as third parameter to the Collection.UpdateOne method. For example:
update := bson.NewDocument(
bson.EC.SubDocumentFromElements(
"$set",
bson.EC.Double("pi", 3.14159),
),
)
collection.UpdateOne(ctx, filter, update)
See more on the available update operators in the MongoDB docs (the keys begin with '$').