Using MongoDB with Go

This part of the Go Bookshelf tutorial shows how the sample app stores its persistent data in a MongoDB database.

This page is part of a multi-page tutorial. To start from the beginning and read the setup instructions, go to Go Bookshelf app.

Running MongoDB on Google Compute Engine

If you haven't set up a Mongo instance, you can create a managed one running on top of Google Cloud Platform using Atlas on GCP or mLab. If you'd rather use an unmanaged MongoDB instance running on Compute Engine, check out Bitnami's preconfigured click-to-deploy solution.

For best performance, make sure your MongoDB instance is hosted on Google Cloud Platform and located in the same region as your app.

By default, MongoDB uses port 27017 for communication. After setting up your MongoDB instance, you might need to configure the firewall rules to allow traffic to and from this port. For instances running on Google Cloud Platform, see Using Firewall Rules for instructions.

Configuring settings

  1. Go to the directory that contains the sample code:


    cd $GOPATH/src/


    cd %GOPATH%\src\\GoogleCloudPlatform\golang-samples\getting-started\bookshelf

  2. Open config.go for editing.

  3. Uncomment the following lines:

    // var cred *mgo.Credential
    // DB, err = newMongoDB("localhost", cred)
  4. Replace localhost with the external IP address address of your MongoDB instance. This is the external IP that you noted in the earlier section. You can also find the external IP address by running gcloud compute instances list.

  5. Save and close config.go.

Running the app on your local machine

  1. Run the app to start a local web server:

    cd app
    go run app.go auth.go template.go
  2. Enter this address in your web browser:


Now you can browse the app's web pages and add, edit, and delete books.

Press Control+C to exit the local web server.

Deploying the app to the App Engine flexible environment

  1. In the app directory, enter this command to deploy the sample:

    gcloud app deploy
  2. In your web browser, enter this address. Replace [YOUR_PROJECT_ID] with your project ID:


If you update your app, you can deploy the updated version by entering the same command you used to deploy the app the first time. The new deployment creates a new version of your app and promotes it to the default version. The older versions of your app remain, as do their associated VM instances. Be aware that all of these app versions and VM instances are billable resources.

You can reduce costs by deleting the non-default versions of your app.

To delete an app version:

  1. In the GCP Console, go to the Versions page for App Engine.

    Go to the Versions page

  2. Select the checkbox for the non-default app version you want to delete.
  3. Click Delete to delete the app version.

For complete information about cleaning up billable resources, see the Cleaning up section in the final step of this tutorial.

Application structure

The following diagram shows the how the sample application components are connected to each other:

Bookshelf app deployment process and structure

Understanding the code

This section walks you through the application code and explains how it works.

Handling user submissions with forms

When a user clicks Add Book, the browser navigates to /books/add, and the addFormHandler function in app/app.go renders a form where the user can add a book:


// addFormHandler displays a form that captures details of a new book to add to
// the database.
func addFormHandler(w http.ResponseWriter, r *http.Request) *appError {
	return editTmpl.Execute(w, r, nil)

Image of add/edit Form

The form includes text input fields for Title, Author, Date Published and Description; it also includes some others, which are used in other sections of the tutorial:

<form method="post" enctype="multipart/form-data" action="/books{{if .}}/{{.ID}}{{end}}">
  <div class="form-group">
    <label for="title">Title</label>
    <input class="form-control" name="title" id="title" value="{{.Title}}">
  <div class="form-group">
    <label for="author">Author</label>
    <input class="form-control" name="author" id="author" value="{{.Author}}">
  <div class="form-group">
    <label for="publishedDate">Date Published</label>
    <input class="form-control" name="publishedDate" id="publishedDate" value="{{.PublishedDate}}">
  <div class="form-group">
    <label for="description">Description</label>
    <input class="form-control" name="description" id="description" value="{{.Description}}">
  <div class="form-group">
    <label for="image">Cover Image</label>
    <input class="form-control" name="image" id="image" type="file">
  <button class="btn btn-success">Save</button>
  <input type="hidden" name="imageURL" value="{{.ImageURL}}">
  <input type="hidden" name="createdBy" value="{{.CreatedBy}}">
  <input type="hidden" name="createdByID" value="{{.CreatedByID}}">

Handling form submissions

When a user fills in the form and clicks Save, the following code handles the form's HTTP POST /books action. The code inserts the new book into the database by calling the bookshelf.DB.AddBook() function.


// createHandler adds a book to the database.
func createHandler(w http.ResponseWriter, r *http.Request) *appError {
	book, err := bookFromForm(r)
	if err != nil {
		return appErrorf(err, "could not parse book from form: %v", err)
	id, err := bookshelf.DB.AddBook(book)
	if err != nil {
		return appErrorf(err, "could not save book: %v", err)
	go publishUpdate(id)
	http.Redirect(w, r, fmt.Sprintf("/books/%d", id), http.StatusFound)
	return nil

The AddBook function, defined in db_mongo.go, performs an Insert() operation to add the user's submitted data as a document to the MongoDB collection.

// AddBook saves a given book, assigning it a new ID.
func (db *mongoDB) AddBook(b *Book) (id int64, err error) {
	id, err = randomID()
	if err != nil {
		return 0, fmt.Errorf("mongodb: could not assign a new ID: %v", err)

	b.ID = id
	if err := db.c.Insert(b); err != nil {
		return 0, fmt.Errorf("mongodb: could not add book: %v", err)
	return id, nil

When the user clicks Books, the browser navigates to the /books page, and the ListBooks method displays all the books in the datastore.

The statement db.c.Find(nil) creates a query that selects all documents in the collection. The query includes .Sort("title"), which specifies that the results should be ordered alphabetically by book title.

The query is executed by calling All, which appends all the returned documents to the result slice.

// ListBooks returns a list of books, ordered by title.
func (db *mongoDB) ListBooks() ([]*Book, error) {
	var result []*Book
	if err := db.c.Find(nil).Sort("title").All(&result); err != nil {
		return nil, err
	return result, nil
Was this page helpful? Let us know how we did:

Send feedback about...