Search code examples
mongodbgomgo

How Find function's generic map was created?


I am looking at this example. I would never coome up with solution like this,I would go for bson.raw.

type Movie struct {
    ID        bson.ObjectId `json:"id" bson:"_id,omitempty"`
    Name      string        `json:"name" bson:"name"`
    Year      string        `json:"year" bson:"year"`
    Directors []string      `json:"directors" bson:"directors"`
    Writers   []string      `json:"writers" bson:"writers"`
    BoxOffice BoxOffice     `json:"boxOffice" bson:"boxOffice"`
}

GetMovie function reads data from MongoDB and returns JSON

func (db *DB) GetMovie(w http.ResponseWriter, r *http.Request) {
    vars := mux.Vars(r)
    w.WriteHeader(http.StatusOK)
    var movie Movie
    err := db.collection.Find(bson.M{"_id": bson.ObjectIdHex(vars["id"])}).One(&movie)
    if err != nil {
        w.Write([]byte(err.Error()))
    } else {
        w.Header().Set("Content-Type", "application/json")
        response, _ := json.Marshal(movie)
        w.Write(response)
    }

}

I do not understand how generic map bson.M was created. Why did the author used bson.ObjectIdHex(vars["id"]?


Solution

  • bson.M is a map under the hood:

    type M map[string]interface{}
    

    And this:

    bson.M{"_id": bson.ObjectIdHex(vars["id"])}
    

    Is a composite literal creating a value of type bson.M. It has a single pair where key is "_id" and the associated value is a bson.ObjectId returned by the function bson.ObjectIdHex().

    The document ID to look up and return is most likely coming as a hexadecimal string in vars["id"], and bson.ObjectIdHex() converts (parses) this into an ObjectId.

    Tips: to query a document by ID, easier is to use Collection.FindId, e.g.:

    err := db.collection.FindId(bson.ObjectIdHex(vars["id"])).One(&movie)
    

    Also to avoid a runtime panic in case an invalid ID is stored in vars["id"], you could use bson.IsObjectIdHex() to check it first. For details, see Prevent runtime panic in bson.ObjectIdHex.

    Also, marshaling the result into a byte slice and then writing it to the response is inefficient, the response could be streamed to the output using json.Encoder. For details, see Ouput json to http.ResponseWriter with template.