Update embedded field in MongoDB using Golang

I am trying to update the embedded field “Comments” in MongoDB. Below is the code.

  1. Struct.
package entities
type IMDBRegistry struct {
    MovieName   string                 `json:"moviename,omitempty"`
    Rating      string                 `json:"rating,omitempty"`
    RatingCount int                    `json:"peoplecount,omitempty"`
    Comments    map[string]interface{} `json:"comments,omitempty"`
}
  1. Wrapper written on MongoDB for Update operation.
func UpdateDocument(filterObject interface{}, operation string, update map[string]interface{}) (int64, error) {
    mongoObj := connect.GetMongoObject()
    if mongoObj == nil {
        log.Fatalln(constants.ERR_DB)
        return 0, nil // TODO
    }
    collection := mongoObj.Database(constants.DB_NAME).Collection(constants.COLLECTION_NAME_USER)
    jsonData, err := json.Marshal(filterObject)
    if err != nil {
        log.Println("Error while Marshalling in UpdateDocument")
        return 0, err
    }
    var m interface{}
    json.Unmarshal(jsonData, &m)
    filter := m.(map[string]interface{})
    jsonDataUpdate, err := json.Marshal(update)
    if err != nil {
        return 0, err
    }
    var m1 interface{}
    json.Unmarshal(jsonDataUpdate, &m1)
    updateString := bson.M{operation: update}
    result, err := collection.UpdateOne(context.TODO(), filter, updateString)
    log.Println("Result is ::: ", result)
    if err != nil {
        return 0, err
    } else {
        log.Println("Returning from here.")
       return result.ModifiedCount, nil
    }
}
  1. Code where I am trying to update the “Comments” field , I have tried various operators not just one.
    Overview: I am reading the moviename which is provided for instance moviename exist then on the basis of it I am fetching whole record then storing comments in temporary variable then appending new comment with old ones then trying to save.
func AddComment(params add_comment.PostcommentsParams) middleware.Responder {

    log.Println("Processing request to AddComment.")
    userName := params.Body.UserName
    movieName := params.Body.MovieName
    movieComment := make(map[string]interface{}, 0)
    movieComment["comments"] = params.Body.MovieComment
    if UserNameIsValid(userName) == userName && len(userName) > 0 {
        //Checking if provided moviename exist in DB.
        if MovieNameIsValid(movieName) == movieName && len(movieName) > 0 && len(movieComment) > 0 {
            searchResult, err := ReadDocument(entities.IMDBRegistry{Comments: movieComment}, &entities.IMDBRegistry{})
            if err != nil {
            }
            if searchResult != nil {
                result := searchResult.(entities.IMDBRegistry)
                commentUp := result.Comments
                _, err := UpdateDocument(entities.IMDBRegistry{Comments: result.Comments}, "$push", nil)
                if err != nil {
                }
            }
            //UpdateDocument(entities.IMDBRegistry{Comments: movieComment})
        } else { // If moviename is invalid.
            errMsg := constants.INVALID_MOVIENAME + constants.REQUEST_FAILED
            return add_comment.NewPostcommentsInternalServerError().WithPayload(&models.Error{Code: constants.INTERNAL_ERROR_CODE, Message: &errMsg})
        }
    }
    //Return error if above conditions are not satisfied.
    errMsg := constants.INVALID_USER + constants.REQUEST_FAILED
    return add_comment.NewPostcommentsInternalServerError().WithPayload(&models.Error{Code: constants.INTERNAL_ERROR_CODE, Message: &errMsg})
}

If any other information is needed I will provide . Any help is appreciated .

Hi @Vibhor_Dubey,

Can you share what is actually happening when you run your code and what the expected result is? Right now you’ve posted your code, which is great, but I don’t know if you’re receiving errors, documents are silently not updating, or documents are updating with the wrong information, or something else.

The more details into the actual problem, the easier it will be to find a solution :slight_smile:

Best,

1 Like

@nraboy Firstly thank you for your time.
There are no errors , when I checked the update response it showed “0” , which means nothing is updated. Please let me know if any other information is needed.

Hi @Vibhor_Dubey,

I’m not sure I have enough of your code to be able to sample run it myself, but I’m thinking the problem might be in your data structure.

You have JSON annotations on your fields, but to get proper bindings to document fields you want to use BSON annotations. For example:

type IMDBRegistry struct {
    MovieName   string                 `bson: "moviename" json:"moviename,omitempty"`
    Rating      string                 `bson: "rating" json:"rating,omitempty"`
    RatingCount int                    `bson: "peoplecount" json:"peoplecount,omitempty"`
    Comments    map[string]interface{} `bson: "comments" json:"comments,omitempty"`
}

I’m thinking your filter isn’t working correctly because the field mappings aren’t happening due to the missing BSON annotations.

You might also check out a Golang quickstart series I wrote which includes CRUD and annotations:

https://www.mongodb.com/quickstart/golang-change-streams

Let me know how it goes.

Best,

Hi @nraboy ,

Above I’ve provided wrapper written over MongoDB in 2 nd point . There I am doing marshalling and unmarshalling , i.e is the reason I’ve used JSON data structure .

Repo: GitHub - vibhordubey333/MoviesDB: Microservice written in Golang , where user can save new movies as well as rate, comment them . Functionality is similar to IMDB website where guest can see the movies , logged in users can comment , rate , admin can save new movies . For DB MongoDB is used.

I thought may be using the “map[string]interface{}” data structure is wrong , so I am tried changing my structure also , but no luck :frowning: .

package entities
type IMDBRegistryImproved struct {
MovieName string json:"moviename,omitempty"
Rating string json:"rating,omitempty"
RatingCount int json:"peoplecount,omitempty"
Comments UserComments json:"comments,omitempty"
}

type UserComments struct {
MovieName string bson: "MovieName" json:"MovieName,omitempty" //bson:"MovieName" json:“MovieName,omitempty”
UserName string bson: "UserName" json:"UserName,omitempty" //bson: json:"UserName,omitempty
UserComment string bson: "UserComment" json:"UserComment,omitempty" //json:"UserComment,omitempty
UserRating float32 bson: "UserRating" json:"UserRating,omitempty" //json:"UserRating,omitempty
}

Hi @Vibhor_Dubey,

The manual marshaling and unmarshaling seems unnecessary based strictly on the example in the point you made. Maybe there’s further reason for it in your code, but you should definitely look at using BSON annotations so the marshaling and unmarshaling happens automagically:

@Divjot_Arora, are you able to glance over this and see if you can spot the point of failure in the code?

There’s a lot of stuff going on in the code here. Would it be possible to create a smaller, reproducible example? That might make it easier to spot the issue.