How to Get MongoDB Documents Using Golang

Introduction

If you’re interested in using the Golang language to communicate with your instance of MongoDB, it’s easy to accomplish this with the help of the Golang driver for MongoDB. Once the driver is installed, it’s easy to connect to MongoDB from your Golang script with just a few lines of code. In this article, we’ll show you how to connect to MongoDB and find documents with Golang.

Prerequisites for using the Golang driver for MongoDB

Let’s go over some important prerequisites that need to be in place before proceeding with this tutorial: First, the MongoDB server needs to be running. You can use the mongo command in a terminal or command prompt window to see if it’s running by trying to enter the Mongo Shell. If this returns an error, you’ll know the server isn’t running. The Golang driver for MongoDB needs to be installed, and the environmental variables for Golang need to be set in the bash profile shell script. You can use the go get command to check if a package is installed:

go get go.mongodb.org/mongo-driver/mongo
  • Be sure you have at least a few MongoDB documents already stored in a collection in order to get the most out of the examples in this tutorial.

Create a new Golang script and import the packages for MongoDB

Now that we’ve discussed the system requirements, we can focus on our code. Let’s begin by creating a new file using the .go file extension; you can do this using the touch command in a terminal window. Be sure to create this file in the same directory path as your Golang projects. If you’re not sure of the directory path, type $GOPATH in a terminal or command prompt window, and it should return this information.

Import the MongoDB packages and other Golang package libraries

Our next step will be to place package main at the top of the file. We’ll also use Go’s import() declaration to include all of the necessary packages for the MongoDB API calls. The code below shows the various packages we’re importing in this example, including the mongodb-driver package for Golang:

package main
import (
"context" // manage multiple requests
"fmt" // Println() function
"reflect" // get an object type
"time"
// import 'mongo-driver' package libraries
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/primitive"   
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)

Create a struct object of the MongoDB fields

In order to get the MongoDB data returned by the API call, it’s important to first declare a struct object. This object will contain all of the collection fields you’d like the API call to return.

In the following example, we declare a struct to marshal the MongoDB data outside of the main() function:

type Fields struct {
Name string
Email string
Dept int
}

Note that each field in the struct needs to be accompanied by a data type.

Create a struct object in the Go script for the MongoDB fields returned by API call

Screenshot of a document in MongoDB Compass UI and a Golang script

Connect to MongoDB using the mongo.Connect() method

Next, we’ll declare the main() function, which is where all of the code in the script will be executed:

func main() {

Connect to MongoDB using the package’s Connect() method

After we declare our main() function, we can use the options.Client() method and have it return a options.ClientOptions object. We can then pass that object to the mongo.Connect method to declare a new client instance and check for errors. The code to accomplish this is shown below:

// Declare host and port options to pass to the Connect() method
clientOptions := options.Client().ApplyURI("mongodb://localhost:27017")
fmt.Println("clientOptions type:", reflect.TypeOf( clientOptions ), "\n")
// Connect to the MongoDB and return Client instance
client, err := mongo.Connect(context.TODO(), clientOptions)
if err != nil {
fmt.Println("mongo.Connect() ERROR:", err)
os.Exit(1)
}

Use Golang’s Context package to manage the MongoDB API requests

We’ll also need to declare a new context instance– this can assist with managing timeouts for the MongoDB API requests:

// Declare Context type object for managing multiple API requests
ctx, _ := context.WithTimeout(context.Background(), 15*time.Second)

This context instance, which we named ctx, can be passed to multiple API calls, and it works well when you’re dealing with concurrent channels and multiple goroutines.

Declare a collection instance using the client instance of the mongo-driver package

Now let’s use the := Golang operator to declare a new Collection() instance and assign it to a variable using the client instance we created earlier:

// Access a MongoDB collection through a database
col := client.Database("employees").Collection("New Hires")
fmt.Println("Collection type:", reflect.TypeOf(col), "\n")

Use the FindOne() method to return a MongoDB document in Golang

Once we have a collection object, we can go ahead and make API calls to the MongoDB server using the mongo-driver package.

Use var to declare an instance of the Fields struct object

Here, we use the var statement to declare an instance of the “Fields” struct. The API call can then return document results to this instance:

// declare an instance of the MongoDB fields struct
var result Fields

Call the collection instance’s FindOne() method

We can communicate with MongoDB using FindOne in Golang. The FindOne() method will only return an error object. If you’d like to overwrite the data from the err object used earlier, you’ll need to assign it a new value using the = operator; otherwise, you can use a new variable name (like err2) and use the := declarative operator instead.

Simply pass an empty bson.D{} object to the FindOne() method call since no query or filter is necessary:

// get a MongoDB document using the FindOne() method
err = col.FindOne(context.TODO(), bson.D{}).Decode(&result)

Note that we use the Decode() attribute method to actually get a document– we accomplish this by passing the result struct instance to it.

Parse the result object returned by the mongo-driver API call

When the err object is returned, evaluate it to make sure it has a value of nil, which means that no errors were raised. If there were no errors, you can then get the document’s data by accessing the various attributes of the struct object. An example of this is shown below:

if err != nil {
fmt.Println("Error calling FindOne():", err)
os.Exit(1)
} else {
fmt.Println("FindOne() result:", result)
fmt.Println("FindOne() Name:", result.Name)
fmt.Println("FindOne() Dept:", result.Dept)
}

Use the MongoDB Golang driver to return all of a collection’s documents

Now we’ll pass another empty bson.D{} object to the driver’s Find() method. This step has the MongoDB driver return all of the collection’s documents:

// call the collection's Find() method and return Cursor obj
cursor, err := col.Find(context.TODO(), bson.D{})

Iterate over the MongoDB documents returned by the Golang driver’s Find() method

As we did in the previous example, the first thing we’ll do here is to check if the API call returned any errors by evaluating the err object for the Find() method call:

// Find() method raised an error
if err != nil {
fmt.Println("Finding all documents ERROR:", err)
defer cursor.Close(ctx)

If there are no errors, then we’ll use the cursor object’s Next() method to iterate over the MongoDB documents. As we go through these documents, we’ll check for errors and create a BSON result object in the process:

// If the API call was a success
} else {
// iterate over docs using Next()
for cursor.Next(ctx) {
// Declare a result BSON object
var result bson.M
err := cursor.Decode(&result)

If we find an error, we’ll print it out and exit the application; otherwise, we’ll print the results of the cursor.Decode() method call:

// If there is a cursor.Decode error
if err != nil {
fmt.Println("cursor.Next() error:", err)
os.Exit(1)
// If there are no cursor.Decode errors
} else {
fmt.Println("\nresult type:", reflect.TypeOf(result))
fmt.Println("result:", result)
}
}
}
}

Conclusion

As you can see, it’s not difficult to connect to MongoDB and retrieve documents from a collection using the Golang programming language. In this tutorial, we saw examples of getting a single document as well as all documents, and we learned how to examine the returned object for errors before parsing the results. With these step-by-step instructions, you’ll be able to write your own script to get a MongoDB document with Golang.

Just the Code

Shown below is the example code in its entirety:

package main

import (
    "context" // manage multiple requests
    "fmt"     // Println() function
    "os"
    "reflect" // get an object type
    "time"

    // import 'mongo-driver' package libraries
    "go.mongodb.org/mongo-driver/bson"
    "go.mongodb.org/mongo-driver/mongo"
    "go.mongodb.org/mongo-driver/mongo/options"
)

type Fields struct {
    Name  string
    Email string
    Dept  int
}

func main() {
    // Declare host and port options to pass to the Connect() method
    clientOptions := options.Client().ApplyURI("mongodb://localhost:27017")
    fmt.Println("clientOptions type:", reflect.TypeOf(clientOptions), "\n")

    // Connect to the MongoDB and return Client instance
    client, err := mongo.Connect(context.TODO(), clientOptions)
    if err != nil {
        fmt.Println("mongo.Connect() ERROR:", err)
        os.Exit(1)
    }

    // Declare Context type object for managing multiple API requests
    ctx, _ := context.WithTimeout(context.Background(), 15*time.Second)

    // Access a MongoDB collection through a database
    col := client.Database("employees").Collection("New Hires")
    fmt.Println("Collection type:", reflect.TypeOf(col), "\n")

    // Declare an empty array to store documents returned
    var result Fields

    // Get a MongoDB document using the FindOne() method
    err = col.FindOne(context.TODO(), bson.D{}).Decode(&result)
    if err != nil {
        fmt.Println("FindOne() ERROR:", err)
        os.Exit(1)
    } else {
        fmt.Println("FindOne() result:", result)
        fmt.Println("FindOne() Name:", result.Name)
        fmt.Println("FindOne() Dept:", result.Dept)
    }

    // Call the collection's Find() method to return Cursor obj
    // with all of the col's documents
    cursor, err := col.Find(context.TODO(), bson.D{})

    // Find() method raised an error
    if err != nil {
        fmt.Println("Finding all documents ERROR:", err)
        defer cursor.Close(ctx)

    // If the API call was a success
    } else {
        // iterate over docs using Next()
        for cursor.Next(ctx) {

            // declare a result BSON object
            var result bson.M
            err := cursor.Decode(&result)

            // If there is a cursor.Decode error
            if err != nil {
                fmt.Println("cursor.Next() error:", err)
                os.Exit(1)
               
            // If there are no cursor.Decode errors
            } else {
                fmt.Println("\nresult type:", reflect.TypeOf(result))
                fmt.Println("result:", result)
            }
        }
    }
}

Pilot the ObjectRocket platform free for 30 Days

It's easy to get started. Imagine the time you'll save by not worrying about database management. Let's do this!

PILOT FREE FOR 30 DAYS

Keep in the know!

Subscribe to our emails and we’ll let you know what’s going on at ObjectRocket. We hate spam and make it easy to unsubscribe.