[GO] Mastering MongoDB Integration with Go: A Step-by-Step Developer’s Guide

Mohit Dubey
7 min readFeb 4, 2024

--

MongoDB is a NoSQL database, and NoSQL has many advantages over SQL, such as flexible data models, horizontal scaling, faster queries, and easy development, among others. Read more here: NoSQL vs SQL.

NoSQL is gaining popularity, and as developers, we should know how to use it with our APIs. Learn more about NoSQL here. This post focuses on the integration of MongoDB (NoSQL) with Go, but I would be happy to discuss NoSQL as well. In case of any doubts, please drop a comment, and I will try my best to address it.

Let’s start building the Go APIs powered by MongoDB.

Disclaimer: Here, I have demonstrated the code in a very flat structure for the simplicity of understanding. However, the GitHub link that I will share contains a properly structured project, ready to use as a professional.

Step-1: MongoDB Setup

Here are the installation guidelines for MongoDB (for all operating systems): MongoDB Installation Guidelines.

Please note: Here are the commands for installation on macOS via the terminal.

#Command 1 (Only if XCode CLI is not installed)
> xcode-select --install
#Command 2
> brew tap mongodb/brew
#Command 3
> brew update
#Command 4
> brew install mongodb-community@7.0

To access MongoDB with a GUI, you can install MongoDB Compass. Here is the installation guideline: MongoDB Compass Download.

After installing MongoDB and MongoDB Compass, you have to start the Database service. Here is the command to start the service.

brew services start mongodb-community@7.0

When you want to stop MongoDB, you can run the following command:

brew services stop mongodb-community@7.0

After you have started the MongoDB services, open MongoDB Compass to operate using the GUI. It would look something like this:

After you have started the MongoDB services, open MongoDB Compass to operate using the GUI. It would look something like this:

By default, MongoDB runs on localhost:27017, and the connection string for MongoDB is mongodb://localhost:27017.

Please note: I have created the database mongo-goalng-test, and inside that, I have created a collection called Users. I will use this database and collection in Go integration.

Step-2: Go Project Setup and Dependency Integration

Create a new folder named mongodb-go and open the folder in the IDE. In the terminal, make sure you are inside the mongodb-go folder and then execute the following two commands:

> go mod init mongodb-go
> go get go.mongodb.org/mongo-driver/mongo

This command will add the mod file to your project and then also add the MongoDB dependency. Here is the link to read more about the MongoDB package for Go: https://github.com/mongodb/mongo-go-drive

Step-3: Create a new struct to insert into MongoDB

As you can see in the MongoDB setup, we have declared a new collection Users in MongoDB. Now we will create a new struct, User, in Go. We will define the JSON property names and MongoDB property names for it. Create a new file named user.go and add the following code:

type User struct {
Id primitive.ObjectID `json:"id" bson:"_id"`
Name string `json:"name" bson:"name"`
Age int `json:"age" bson:"age"`
Gender bool `json:"gender" bson:"gender"`
}

Step-4: Adding the mongoDB config

Add a new file mongoDBConnection.go and inside that file add a new function SetupMongoDB.

//File: mongoDBConnection.go
// Open new connection
func SetupMongoDB() (*mongo.Collection, *mongo.Client, context.Context, context.CancelFunc) {
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
client, err := mongo.Connect(ctx, options.Client().ApplyURI("mongodb://localhost:27017"))
if err != nil {
panic(fmt.Sprintf("Mongo DB Connect issue %s", err))
}
err = client.Ping(ctx, readpref.Primary())
if err != nil {
panic(fmt.Sprintf("Mongo DB ping issue %s", err))
}
collection := client.Database("mongo-golang-test").Collection("Users")
return collection, client, ctx, cancel
}

// Close the connection
func CloseConnection(client *mongo.Client, context context.Context, cancel context.CancelFunc) {
defer func() {
cancel()
if err := client.Disconnect(context); err != nil {
panic(err)
}
fmt.Println("Close connection is called")
}()
}

As mentioned above, MongoDB by default runs on mongodb://localhost:27017. In case you are running it on some other port, please mention that connection string here. You can copy the connection string from MongoDB Compass.

Step-5: Add handlers to interact with the mongoDB

We will write four functions in our handler.go. Insert, Delete, FetchAll and FetchOne

Step-5a: Insert object into MongoDB using GO

Here are the steps to write an API to insert the data into mongoDB

  • Create a new method CreateUser of type post
  • This method will read the request body sent by the user and match it with our user object using json decoder.
  • Open the MongoDB connection
  • Write the object
  • Send the object back on successful write else send the error
  • Close the mongoDB connection

Below is the code for the same:

//File: Handler.go
func CreateUser(w http.ResponseWriter, r *http.Request) {
user := dto.User{}
err := json.NewDecoder(r.Body).Decode(&user)
if err != nil {
fmt.Fprintf(w, "Error in reading post body %s", err)
return
}
collection, client, context, cancel := SetupMongoDB()
defer CloseConnection(client, context, cancel)
user.Id = primitive.NewObjectID()
result, err := collection.InsertOne(context, user)
if err != nil {
fmt.Fprintf(w, fmt.Sprintf("Error in Creating user %v", err))
return
}
fmt.Printf("Inserted user %v", result.InsertedID)
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusCreated)
if err := json.NewEncoder(w).Encode(*user); err != nil {
panic(err)
}
}

CreateUser curl:

curl --location 'http://localhost:8080/createUser' \
--header 'Content-Type: application/json' \
--data '{
"name": "Moh",
"age": 2,
"gender": false
}'

Step-5b: Fetch all records from MongoDB using GO

Here are the steps to write an API to fetch records from MongoDB using GO

  • Create a new method FindUsers of type GET
  • Open the MongoDB Connection
  • Fetch all the records
  • Traverse each record and append to an array/ Slice
  • Send the array back on successful fetch else send the error
  • Close the connection

Below is the code

//File: Handler.go
func (uh UserHandler) FindUsers(w http.ResponseWriter, r *http.Request) {
collection, client, context, cancel := SetupMongoDB()
u := make([]dto.User, 0, 10)
filter := bson.D{}
cursor, err := collection.Find(context, filter)
if err == mongo.ErrNoDocuments {
fmt.Println("No document found")
} else if err != nil {
fmt.Printf("Error in mongo %v", err)
}
if err != nil {
fmt.Fprintf(w, fmt.Sprintf("Error in Finding user %v", err))
}
defer CloseConnection(client, context, cancel)
defer cursor.Close(context)
for cursor.Next(context) {
var result User
err := cursor.Decode(&result)
if err != nil {
log.Fatal(err)
}
u = append(u, result)
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
if err := json.NewEncoder(w).Encode(u); err != nil {
fmt.Fprintf(w, fmt.Sprintf("Cannot parse %v", err))
}
}

FetchUsers curl:

curl --location 'http://localhost:8080/users'

Step-5c: Fetch single record from MongoDB using GO

Here are the steps to fetch a single record from the MongoDB using GO API

  • Create a new function FetchUser of type GET
  • Read the item id from the request
  • Open the MongoDB connection
  • Fetch the record
  • Send back the record else send not found error
  • Close the connection
//File: Handler.go
func (uh UserHandler) FindUser(w http.ResponseWriter, r *http.Request) {
id := mux.Vars(r)["user_id"]
collection, client, context, cancel := SetupMongoDB()

defer CloseConnection(client, context, cancel)

oid, err := primitive.ObjectIDFromHex(id)
if err != nil {
fmt.Fprintf(w, fmt.Sprintf("Error %v", err))
}

u := dto.User{}
filter := bson.D{{Key: "_id", Value: oid}}

err = collection.FindOne(context, filter).Decode(&u)
if err == mongo.ErrNoDocuments {
fmt.Println("No document found")
fmt.Fprintf(w, fmt.Sprintf("Error %v", err))
} else if err != nil {
fmt.Printf("Error in mongo %v", err)
fmt.Fprintf(w, fmt.Sprintf("Error %v", err))
}

w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)

if err := json.NewEncoder(w).Encode(*u); err != nil {
panic(err)
}
}

FetchUser curl:

curl --location 'http://localhost:8080/users/<Item_id_goes_here>'

Step-5d: Delete user from MongoDB using GO

Here are the steps to delete the user from MongoDB using GO API

  • Create a new function DeleteUser of type GET
  • Read the item id from the request
  • Open the MongoDB connection
  • Delete the record from MongoDB and get the delete count
  • Send back the delete count and item id
  • Close the connection
func (uh UserHandler) DeleteUser(w http.ResponseWriter, r *http.Request) {
id := mux.Vars(r)["user_id"]
collection, client, context, cancel := SetupMongoDB()

defer CloseConnection(client, context, cancel)

oid, err := primitive.ObjectIDFromHex(id)
if err != nil {
fmt.Fprintf(w, fmt.Sprintf("Error %v", err))
}
filter := bson.D{{Key: "_id", Value: oid}}

result, err := collection.DeleteOne(context, filter)
if err != nil {
fmt.Fprintf(w, fmt.Sprintf("Error in Deleting user %v", err))
}

resultStr := fmt.Sprintf("Results deleted %v, id of the item %v", result.DeletedCount, oid)
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
fmt.Fprintln(w, resultStr)
}

DeleteUser curl:

curl --location 'http://localhost:8080/users/delete/<item_id_goes_here>'

Step-6: Create the main.go and create the API handlers and define server and port

Now is the time to connect all your pieces together. So let's first create a new file main.go. In main.go, define a new function Startup with below functionality:

  • Create a new router
  • Define all the handlers
  • Define the server and port to run at
//File: main.go
func Startup() {
router := mux.NewRouter()

router.HandleFunc("/create_user", CreateUser).Methods(http.MethodPost)
router.HandleFunc("/users/{user_id}", FindUser).Methods(http.MethodGet)
router.HandleFunc("/users", FindUsers).Methods(http.MethodGet)
router.HandleFunc("/users/delete/{user_id}", DeleteUser).Methods(http.MethodGet)

fmt.Println("Running at localhost:8080")
err := http.ListenAndServe("localhost:8080", router)
if err != nil {
panic("Cannot start the server")
}
}

Here we have defined four handlers:

  • /create_user: It is of type post, so you will send the user json object in request body
  • /users/{user_id}: This is to fetch a single user. It will return a user json object
  • /users: This will fetch all the users. It will return an array of users
  • /delete/{user_id}: This will read the user_id from the request and will attempt to delete the user

Step-7: Run the main.go

Here is the command to run your go service

go run main.go

Feel free to explore the complete code here: mongo-db. Happy coding!!! The github link that I have shared contains a proper structured project and may have code placed in different files.

This article is your backstage pass to a hands-on tutorial, unraveling the secrets of building a MongoDB service with Go. Are you ready for the thrill?

👉 Your Mission:

  1. Interact: Share your thoughts in the comments. Got questions? Fire away! 💬
  2. Show Your Love: Clap as much as you’re thrilled by the content. Your applause fuels our coding expedition! 👏
  3. Bookmark for Future Adventures: Save this article for quick access to the coding gems within.
  4. Follow the Trail: Curious for more content? Follow the profile for future insights and coding escapades.

--

--

Mohit Dubey

Associate Director @ VerSe Innovation(Dailyhunt and Josh) | Gen AI, Machine Learning and Deep Learning | mobile full stack | iOS Swift, React Native, KMP | GO