mgo is a rich MongoDB driver that facilitates developers to write applications that talk to MongoDB without the need for the Mongo shell. The Go application can talk easily with MongoDB for all its CRUD operations using the mgo driver. It is an open-source implementation that can be used and modified freely. It is maintained by Labix. We can think it of as a wrapper around the MongoDB API. Installing the package is very simple, refer to the following command:
go get gopkg.in/mgo.v2
This installs the package in $GOPATH. Now, we can refer the package to our Go programs, as follows:
import "gopkg.in/mgo.v2"
Let us write a simple program that talks to MongoDB and inserts The Dark Knight movie record:
package main import ( "fmt" "log" mgo "gopkg.in/mgo.v2" "gopkg.in/mgo.v2/bson" ) // Movie holds a movie data type Movie struct { Name string `bson:"name"` Year string `bson:"year"` Directors []string `bson:"directors"` Writers []string `bson:"writers"` BoxOffice `bson:"boxOffice"` } // BoxOffice is nested in Movie type BoxOffice struct { Budget uint64 `bson:"budget"` Gross uint64 `bson:"gross"` } func main() { session, err := mgo.Dial("127.0.0.1") if err != nil { panic(err) } defer session.Close() c := session.DB("appdb").C("movies") // Create a movie darkNight := &Movie{ Name: "The Dark Knight", Year: "2008", Directors: []string{"Christopher Nolan"}, Writers: []string{"Jonathan Nolan", "Christopher Nolan"}, BoxOffice: BoxOffice{ Budget: 185000000, Gross: 533316061, }, } // Insert into MongoDB err = c.Insert(darkNight) if err != nil { log.Fatal(err) } // Now query the movie back result := Movie{} // bson.M is used for nested fields err = c.Find(bson.M{"boxOffice.budget": bson.M{"$gt": 150000000}}).One(&result) if err != nil { log.Fatal(err) } fmt.Println("Movie:", result.Name) }
If you observe the code, we imported the mgo package as well as the bson package. Next, we created the structs that model our JSON to be inserted into the DB. In the main function, we created a session using the mgo.Dial function. After that, we fetched a collection using the DB and C functions in a chained manner:
c := session.DB("appdb").C("movies")
Here, c stands for collection. We are fetching the movies collection from appdb. Then, we are creating a struct object by filling in data. Next, we used the Insert function on the c collection to insert darkNight data into the collection. This function can also take a list of struct objects to insert a batch of movies. Then, we used the Find function on the collection to read a movie with a given criteria. Here, the criteria (querying) is formed differently compared to the one we used in the shell. Since Go is not the JavaScript shell, we need a translator that can convert a normal filter query to the MongoDB understandable query. The bson.M function is designed for that in mgo package:
bson.M{"year": "2008"}
But, what if we need to perform advanced queries with operators? We can do this by just replacing the plain JSON syntax with the bson.M function. We can find a movie from the database whose budget is more than $150,000,000 with this query:
bson.M{"boxOffice.budget": bson.M{"$gt": 150000000}}
If you contrast this with the shell command, we just added bson.M in front of the JSON query and wrote the remaining query as it is. The operator symbol should be a string here ("$gt").
One more notable thing in the struct definition is that we added a bson:identifier tag to each field. Without this, Go stores the BoxOffice as boxoffice. So, in order for Go to maintain the CamelCase, we add these tags. Now, let us run this program and see the output:
go run mgoIntro.go
The output looks like the following:
Movie: The Dark Knight
The result from a query can be stored in a new struct and can be serialized to JSON for the client to use.