This question already has answers here:
How would I update multiple records based on different key in Mongo in one query?
(1 answer)
MongoDB update array of documents and replace by an array of replacement documents
(1 answer)
Closed last month.
I am trying to update a collection of multiple data in MongoDB using Golang at the same time, instead, it updates only one record, I'm using a for loop to perform this action
My filter code
if len(list_phone) > 1 {
for i := 0; i < len(list_phone); i++ {
update_userPhone, err := helpers.UpdatePhone(list_phone[i]["phone"].(string), list_phone[i]["email"].(string))
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(`{"status:":"error", "error": true, "msg": "Something went wrong" }`))
return
}
json.NewEncoder(w).Encode(update_userPhone)
return
}
}
my update function
func UpdatePhone(phone string, email string) (bool, error) {
userCollection, _ := GetDBCollection("users")
ctx, cancel := context.WithTimeout(context.Background(), 100*time.Second)
id := email
filter := bson.M{"email": id}
update := bson.M{"$set": bson.M{"phone": phone}}
_, err := userCollection.UpdateOne(ctx, filter, update)
defer cancel()
if err != nil {
return false, err
}
return true, err
}
Related
I want to bulk update collection by slice of objectid
Here is the function for updatemany
func BulkDeleteEmailContentFieldByIds(ids []primitive.ObjectID) error {
filter := bson.M{"_id": bson.M{"$in": ids}}
update := bson.D{{"$unset", bson.D{{"email_content", 1}}}}
result, err := collection.UpdateMany(ctx, filter, update)
if err != nil {
return err
}
pp.Printf("Bulk delete removed %v document(s)\n", result.ModifiedCount)
return nil
}
var trackingLogIds []primitive.ObjectID
for _, v := range userDocs {
wg.Add(1)
go func(v bson.M) {
defer wg.Done()
// do something to return objectID
trackingLogIds = append(trackingLogIds, emaDoc["_id"].(primitive.ObjectID))
}(v)
}
emadb.BulkDeleteEmailContentFieldByIds(trackingLogIds)
Is the slice trackingLogIds is the correct way to search for documents with objectId
And is the query for updatemany i doing is right?
If not then how can i improve it.
Thanks
I had test the function i provided and its working as expected.
Find all document in slice of objectid and unset the field email_content
I have this method:
func GetPostBySlug(slug string) (PostWithCategory, error) {
post := PostWithCategory{}
filter := bson.M{
"slug": slug,
}
database, error := Database.GetMongoDatabase()
if error != nil {
println(error)
}
match := bson.D{{"$match", bson.D{{"slug", slug}}}}
lookup := bson.D{{"$lookup", bson.D{{"from", categories.Model_name}, {"localField", "category"}, {"foreignField", "_id"}, {"as", "category"}}}}
unwind := bson.D{{"$unwind", bson.D{{"path", "$category"}, {"preserveNullAndEmptyArrays", false}}}}
collection := database.Collection(model_name)
cursor, err := collection.Aggregate(context.TODO(), mongo.Pipeline{match, lookup, unwind})
if err != nil {
return post, err
}
var results []PostWithCategory
if err = cursor.All(context.TODO(), &results); err != nil {
panic(err)
}
fmt.Println(results)
if len(results) > 0 {
post = results[0]
}
return post, err
}
If I remove "unwind" stage from Aggregate(), I will get my document but with empty array instead of category. If I keep it, all the fields become "null" in the document.
Why is this so hard 😠Maybe there is some other way around? The goal is simple. I have an ID of the category in the post and in above method I want to return the post with category object (which is stored in other collection). In node.js with mongoose there is a very simple method called "populate", so I need to perform similar operation here :(
I'm trying to make a function that watches the database for a certain document with a certain id to update but it does not work. It just stays alive while updating the document while the function should return. I've tried multiple things and the rest of the code works fine. When i remove the id part and listen for all document updates in that collection the function does as it should
func iterateChangeStream(routineCtx context.Context,stream *mongo.ChangeStream, chn chan string) {
defer stream.Close(routineCtx)
for stream.Next(routineCtx) {
var data bson.M
if err := stream.Decode(&data); err != nil {
fmt.Println(err)
}
chn <- "updated"
err := stream.Close(routineCtx)
if err != nil {
return
}
return
}
return
}
func (s Storage) ListenForScannerUpdateById(id primitive.ObjectID) {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
defer cancel()
chn := make(chan string)
coll := s.db.Collection("scanners")
scan, err := s.GetScannerById(id)
fmt.Println(scan)
matchPipeline := bson.D{
{
"$match", bson.D{
{"operationType", "update"},
{"fullDocument._id", bson.D{
{"$eq", id},
}},
},
},
}
scannerStream, err := coll.Watch(ctx, mongo.Pipeline{matchPipeline})
if err != nil {
err := scannerStream.Close(ctx)
if err != nil {
panic( err)
}
fmt.Printf("err: %v", err)
}
routineCtx, _ := context.WithCancel(context.Background())
go iterateChangeStream(routineCtx, scannerStream, chn)
msg, _ := <- chn
defer close(chn)
fmt.Println(msg)
return
}
Ok, so after reading the documentation for a seccond time i found this:
For update operations, this field only appears if you configured the change stream with fullDocument set to updateLookup. This field then represents the most current majority-committed version of the document modified by the update operation. This document may differ from the changes described in updateDescription if other majority-committed operations modified the document between the original update operation and the full document lookup.
so after setting the fullDocument option to updateLookup like this it works perfect:
scannerStream, err := coll.Watch(ctx, mongo.Pipeline{matchPipeline}, options.ChangeStream().SetFullDocument(options.UpdateLookup))
I have a problem finding an objectid through the query param called id.
I can see the id that arrives at the function until the moment of doing the query.
But when I try to use ObjectIDFromHex it returns 00000000000000000000000 and doesn't get the document from mongodb.
I'll leave a screenshot so you can see the full problem.
screenshot with IDE
The code is this.
func RetrieveUser(ID string) (models.User, error) {
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
defer cancel()
db := MongoCN.Database("mydatabase")
col := db.Collection("users")
var user models.User
objID, _ := primitive.ObjectIDFromHex(ID)
fmt.Println(ID)
fmt.Println(objID)
condition := bson.M{
"_id": objID,
}
err := col.FindOne(ctx, condition).Decode(&user)
user.Password = ""
if err != nil {
fmt.Println("User not found" + err.Error())
return user, err
}
return user, nil
}
I need to build a query using comparison operators, equivalent of db.inventory.find( { qty: { $gt: 20 } using the official driver. Any idea how to do that?
Connecting to a server is something like:
client, err := mongo.NewClient("mongodb://foo:bar#localhost:27017")
if err != nil { log.Fatal(err) }
err = client.Connect(context.TODO())
if err != nil { log.Fatal(err) }
Then obtain the inventory mongo.Collection like:
coll := client.Database("baz").Collection("inventory")
Then you can execute your query using Collection.Find() like:
ctx := context.Background()
cursor, err := coll.Find(ctx,
bson.NewDocument(
bson.EC.SubDocumentFromElements("qty",
bson.EC.Int32("$gt", 20),
),
),
)
defer cursor.Close(ctx) // Make sure you close the cursor!
Reading the results using the mongo.Cursor:
doc := bson.NewDocument()
for cursor.Next(ctx) {
doc.Reset()
if err := cursor.Decode(doc); err != nil {
// Handle error
log.Printf("cursor.Decode failed: %v", err)
return
}
// Do something with doc:
log.Printf("Result: %v", doc)
}
if err := cursor.Err(); err != nil {
log.Printf("cursor.Err: %v", err)
}
Note: I used a single bson.Document value to read all documents, and used its Document.Reset() in the beginning of each iteration to clear it and "prepare" it to read a new document into it. If you want to store the documents (e.g. in a slice), then you can obviously not do this. In that case just create a new doc in each iteration like doc := bson.NewDocument().