Creating a CRUD application using GO and MongoDB

Pawan Kumar
3 min readDec 23, 2019

--

Recently I was going through some videos on www.youtube.com and a link popped up as ”HOT UPCOMING LANGUAGES in 2020". Out of curiosity I opened it and got to know about GO. After reading about it, I decided to give it a try and Voila!!!. It was FUN :).

So I tried to demonstrate CRUD operations through this post, keeping it as simple as I can. So let's GO…

The first step would be to install the MongoDB driver using go get i.e

go get github.com/mongodb/mongo-go-driver

There might be a warning displaying something likepackage go.mongodb.org/mongo-driver: no Go files in (...). Don’t PANIC. This is expected output from go get.

I’ve created three files named main.go ,db.go and controllers.go. in /src folder under the directory mongoCRUD. So the structure looks like

src/
mongoCRUD/
main.go # main file containing routes
db.go #for Database connection
controllers.go #Handelers for routes

Let’s go to the anatomy of files one by one, starting with main.go

package mainimport (
"github.com/gorilla/mux"
"log"
"net/http"
)

func main() {
route := mux.NewRouter()
s := route.PathPrefix("/api").Subrouter() //Base Path//Routess.HandleFunc("/createProfile", createProfile).Methods("POST")
s.HandleFunc("/getAllUsers", getAllUsers).Methods("GET")
s.HandleFunc("/getUserProfile", getUserProfile).Methods("POST")
s.HandleFunc("/updateProfile", updateProfile).Methods("PUT")
s.HandleFunc("/deleteProfile/{id}", deleteProfile).Methods("DELETE")
log.Fatal(http.ListenAndServe(":8000", s)) // Run Server
}

I’ve used packagegorilla/mux which implements a request router and dispatcher for matching incoming requests to their respective handlers.HandleFunc registers a new route with a matcher for the URL path.

db.go

package mainimport (
"context"
"fmt"
"log"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
func db() *mongo.Client {clientOptions := options.Client().ApplyURI("mongodb://localhost:27017")// Connect to //MongoDBclient, err := mongo.Connect(context.TODO(), clientOptions)
if err != nil {
log.Fatal(err)
}
// Check the connection
err = client.Ping(context.TODO(), nil)
if err != nil {
log.Fatal(err)
}
fmt.Println("Connected to MongoDB!")
return client
}

A connection is set up using mongo.Connect(context.TODO(), clientOptions) .Package context tells about like deadlines, cancellation signals.Further TODO() is used when it’s unclear which Context to use or it is not available.clientOptions contains options like pool size,authentication.In the end client returns *mongo.Client which will be used to access different collections.

Now we will go through each function of controllers.go .But before that, we will be accessing users collection as

var userCollection = db().Database("goTest").Collection("users") where db() contains the *mongo.Client from db.go. Besides we have used user struct to store information.

type user struct{
Name string `json:"name"`
City string `json:"city"`
Age int `json:"age"`
}

CREATE

func createProfile(w http.ResponseWriter, r *http.Request) {w.Header().Set("Content-Type", "application/json") // for adding       //Content-typevar person usererr := json.NewDecoder(r.Body).Decode(&person) // storing in person   //variable of type userif err != nil {fmt.Print(err)}insertResult, err := userCollection.InsertOne(context.TODO(),person)
if err != nil {
log.Fatal(err)
}
json.NewEncoder(w).Encode(insertResult.InsertedID) // return the //mongodb ID of generated document}

READ

func getUserProfile(w http.ResponseWriter, r *http.Request) {w.Header().Set("Content-Type", "application/json")var body usere := json.NewDecoder(r.Body).Decode(&body)if e != nil {
fmt.Print(e)
}
var result primitive.M // an unordered representation of a BSON //document which is a Maperr := userCollection.FindOne(context.TODO(), bson.D{{"name", body.Name}}).Decode(&result)if err != nil {
fmt.Println(err)
}
json.NewEncoder(w).Encode(result) // returns a Map containing //mongodb document
}

UPDATE

func updateProfile(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
type updateBody struct {
Name string `json:"name"` //value that has to be matched
City string `json:"city"` // value that has to be modified
}
var body updateBody
e := json.NewDecoder(r.Body).Decode(&body)
if e != nil {
fmt.Print(e)
}
filter := bson.D{{"name", body.Name}} // converting value to BSON after := options.After // for returning updated document returnOpt := options.FindOneAndUpdateOptions{
ReturnDocument: &after,
}
update := bson.D{{"$set", bson.D{{"city", body.City}}}}updateResult := userCollection.FindOneAndUpdate(context.TODO(), filter, update, &returnOpt)var result primitive.M_ = updateResult.Decode(&result)json.NewEncoder(w).Encode(result)
}

DELETE

func deleteProfile(w http.ResponseWriter, r *http.Request) {w.Header().Set("Content-Type", "application/json")
params := mux.Vars(r)["id"] //get Parameter value as string
_id, err := primitive.ObjectIDFromHex(params) // convert params to //mongodb Hex IDif err != nil {
fmt.Printf(err.Error())
}
opts := options.Delete().SetCollation(&options.Collation{}) // to //specify language-specific rules for string comparison, such as //rules for lettercaseres, err := userCollection.DeleteOne(context.TODO(), bson.D{{"_id", _id}}, opts)if err != nil {
log.Fatal(err)
}
json.NewEncoder(w).Encode(res.DeletedCount) // return number of //documents deleted}

In the end run the application using go run *go .

Here is git repository for the whole code. I hope this tutorial was useful to get some insights into CRUD application.

Get here POSTMAN import link for APIs.

References :

PS: This is my first article. So any changes or suggests are heartly welcomed.

--

--

Pawan Kumar

A Technology enthusiast, affectionate for Data structures and algorithms, Back end Developer, fervent learner, an ardent Bibliophile.