Advice when moving from the mgo to official mongodb driver for golang

This is an except of code I have which uses goji and the mgo driver, I want to change this to use the official driver for golang:

func main() {
            session, err := mgo.Dial("mongo")
    
            if err != nil {
                    panic(err)
            }
    
            defer session.Close()
            session.SetMode(mgo.Monotonic, true)
            ensureIndex(session)
    
            mux := goji.NewMux()
            mux.HandleFunc(pat.Get("/cars"), allCars(session))
            mux.HandleFunc(pat.Post("/cars"), addCar(session))
            mux.HandleFunc(pat.Get("/cars/:vin"), carByVIN(session))
            mux.HandleFunc(pat.Delete("/cars/:vin"), deleteCar(session))
            http.ListenAndServe(":8080", mux)
    }
    
    func allCars(s *mgo.Session) func(w http.ResponseWriter, r *http.Request) {
        return func(w http.ResponseWriter, r *http.Request) {
                session := s.Copy()
                defer session.Close()

                c := session.DB("carsupermarket").C("cars")

                var cars []vehicle
                err := c.Find(bson.M{}).All(&cars)
                if err != nil {
                        errorWithJSON(w, "Database error", http.StatusInternalServerError)
                        log.Println("Failed get all cars: ", err)
                        return
                }

                respBody, err := json.MarshalIndent(cars, "", "  ")
                if err != nil {
                        log.Fatal(err)
                }

                responseWithJSON(w, respBody, http.StatusOK)
        }
}

In terms of passing connectivity / session information to my goji handler functions what would people recommend ?, a pointer to a collection ?

Hey @Chris_Adkin thanks for the question and sorry about the slow reply!

Here’s an example of your provided code using the Go Driver:

func main() {
	client, err := mongo.Connect(
		context.Background(),
		options.Client().ApplyURI("mongo").SetReadPreference(readpref.Primary()))
	if err != nil {
		panic(err)
	}
	defer client.Disconnect(context.Background())

	cars := client.Database("carsupermarket").Collection("cars")
	ensureIndex(cars)

	mux := goji.NewMux()
	mux.HandleFunc(pat.Get("/cars"), allCars(cars))
	mux.HandleFunc(pat.Post("/cars"), addCar(cars))
	mux.HandleFunc(pat.Get("/cars/:vin"), carByVIN(cars))
	mux.HandleFunc(pat.Delete("/cars/:vin"), deleteCar(cars))
	http.ListenAndServe(":8080", mux)
}

func allCars(cars *mongo.Collection) func(w http.ResponseWriter, r *http.Request) {
	return func(w http.ResponseWriter, r *http.Request) {
		cursor, err := cars.Find(r.Context(), bson.M{})
		if err != nil {
			errorWithJSON(w, "Database error", http.StatusInternalServerError)
			log.Println("Failed to find cars: ", err)
			return
		}
		defer cursor.Close(r.Context())

		var cars []vehicle
		err = cursor.All(r.Context(), &cars)
		if err != nil {
			errorWithJSON(w, "Database error", http.StatusInternalServerError)
			log.Println("Failed get all cars: ", err)
			return
		}

		respBody, err := json.MarshalIndent(cars, "", "  ")
		if err != nil {
			log.Fatal(err)
		}

		responseWithJSON(w, respBody, http.StatusOK)
	}
}

Important differences from mgo:

  • The pattern of “copying and closing” a session when running MongoDB operations is not required with the Go Driver.
  • All Go Driver functions that perform network I/O accept a Context parameter used for timeout/cancellation. The example code uses the Context from the http.Request to cancel MongoDB operations if the HTTP request is cancelled.
  • The Monotonic mode is a behavior specific to mgo and has no direct analog in the Go Driver. The closest analog in the Go Driver is using read preference “primary”. Note that in the example code above, read preference “primary” is set at the Client level, but it can also be set at the Database or Collection level.
1 Like