We're planting a tree for every job application! Click here to learn more

MongoDB Driver for Golang Tutorial

Eduardo Henrique da Silva Freitas

17 Jun 2019

4 min read

MongoDB Driver for Golang Tutorial
  • Go

After years relying on Community drivers like mgo and globalsign/mgo, last year MongoDB announced they were building it’s own solution. Last March they released the version 1.0.0, so let’s see how to make some normal operations using the Official driver.

First of all, you need to download the driver using go get.

go.mongodb.org/mongo-driver/mongo

Assuming your MongoDB installation is using the default setting, your method should be like this:

package main

import (
    "context"
    "log"

    "go.mongodb.org/mongo-driver/mongo"
    "go.mongodb.org/mongo-driver/mongo/options"
    "go.mongodb.org/mongo-driver/mongo/readpref"
)

func GetClient() *mongo.Client {
    clientOptions := options.Client().ApplyURI("mongodb://localhost:27017")
    client, err := mongo.NewClient(clientOptions)
    if err != nil {
        log.Fatal(err)
    }
    err = client.Connect(context.Background())
    if err != nil {
        log.Fatal(err)
    }
    return client
}

To test the connection to the mongo, we can call a function called Ping, and check if return any error. Otherwise, out connection was successful.

func main() {
    c := GetClient()
    err := c.Ping(context.Background(), readpref.Primary())
    if err != nil {
        log.Fatal("Couldn't connect to the database", err)
    } else {
        log.Println("Connected!")
    }
}

Now for the next examples I created a database called civilact and a collection heroes and add the followings documents:

{ 
    "_id" : ObjectId("5d0574824d9f7ff15e989171"), 
    "name" : "Tony Stark", 
    "alias" : "Iron Man", 
    "signed" : true
}
{ 
    "_id" : ObjectId("5d0574d74d9f7ff15e989172"), 
    "name" : "Steve Rodgers", 
    "alias" : "Captain America", 
    "signed" : false
}
{ 
    "_id" : ObjectId("5d0574e94d9f7ff15e989173"), 
    "name" : "Vision", 
    "alias" : "Vision", 
    "signed" : true
}
{ 
    "_id" : ObjectId("5d0575344d9f7ff15e989174"), 
    "name" : "Clint Barton", 
    "alias" : "Hawkeye", 
    "signed" : false
}

To work with these documents, would be better if we create a struct that represents all the Fields and their json names.

type Hero struct {
    Name   string `json:"name"`
    Alias  string `json:"alias"`
    Signed bool   `json:"signed"`
}

Now let's create a Method that will return all Heroes expecting 2 parameters: MongoDB Client and a bson.M that represents a filter. Is this filter is empty, the method will return all documents.

import (
    "context"
    "log"

    "go.mongodb.org/mongo-driver/bson"
    "go.mongodb.org/mongo-driver/mongo"
    "go.mongodb.org/mongo-driver/mongo/options"
    "go.mongodb.org/mongo-driver/mongo/readpref"
)

func ReturnAllHeroes(client *mongo.Client, filter bson.M) []*Hero {
    var heroes []*Hero
    collection := client.Database("civilact").Collection("heroes")
    cur, err := collection.Find(context.TODO(), filter)
    if err != nil {
        log.Fatal("Error on Finding all the documents", err)
    }
    for cur.Next(context.TODO()) {
        var hero Hero
        err = cur.Decode(&hero)
        if err != nil {
            log.Fatal("Error on Decoding the document", err)
        }
        heroes = append(heroes, &hero)
    }
    return heroes
}

The breakdown is:

  1. Create a collection that represents the collection in the database;
  2. Ask the collection to return a cursor of with the elements based oh the filter (in this case the filter is empty, so will return all elements);
  3. Iterate this cursor and Decode each document to a Hero type;
  4. Append the Hero decoded in the heroes array.

If we run inside the main function, our return will be:

heroes := ReturnAllHeroes(c, bson.M{})
for _, hero := range heroes {
    log.Println(hero.Name, hero.Alias, hero.Signed)
}

2019/06/15 21:07:00 Tony Stark Iron Man true
2019/06/15 21:07:00 Steve Rodgers Captain America false
2019/06/15 21:07:00 Vision Vision true
2019/06/15 21:07:00 Clint Barton Hawkeye false

To retrieve just the Heroes whom signed the Sokovia Accords, we just need to change the filter.

heroes := ReturnAllHeroes(c, bson.M{"signed": true})

2019/06/15 21:18:04 Tony Stark Iron Man true
2019/06/15 21:18:04 Vision Vision true

To retrieve just one Hero, our new method will be like this:

func ReturnOneHero(client *mongo.Client, filter bson.M) Hero {
    var hero Hero
    collection := client.Database("civilact").Collection("heroes")
    documentReturned := collection.FindOne(context.TODO(), filter)
    documentReturned.Decode(&hero)
    return hero
}

The call will be:

    hero := ReturnOneHero(c, bson.M{"name": "Vision"})
    log.Println(hero.Name, hero.Alias, hero.Signed)

    2019/06/15 22:55:44 Vision Vision true

Now, to increase our collection of Heroes and insert, for example Doctor Strange: The new method will be like this:

func InsertNewHero(client *mongo.Client, hero Hero) interface{} {
    collection := client.Database("civilact").Collection("heroes")
    insertResult, err := collection.InsertOne(context.TODO(), hero)
    if err != nil {
        log.Fatalln("Error on inserting new Hero", err)
    }
    return insertResult.InsertedID
}

That's how we method will be used and checked by our previous method ReturnOneHero:

hero = Hero{Name: "Stephen Strange", Alias: "Doctor Strange", Signed: true}
insertedID := InsertNewHero(c, hero)
log.Println(insertedID)
hero = ReturnOneHero(c, bson.M{"alias": "Doctor Strange"})
log.Println(hero.Name, hero.Alias, hero.Signed)

Great! We added a Sorcerer Supreme in our Heroes collection, but what if he didn't like and asked us to remove him from it? Well, that's why we need a RemoveOneHero method.

func RemoveOneHero(client *mongo.Client, filter bson.M) int64 {
    collection := client.Database("civilact").Collection("heroes")
    deleteResult, err := collection.DeleteOne(context.TODO(), filter)
    if err != nil {
        log.Fatal("Error on deleting one Hero", err)
    }
    return deleteResult.DeletedCount
}

And that's how we check:

heroesRemoved := RemoveOneHero(c, bson.M{"alias": "Doctor Strange"})
log.Println("Heroes removed count:", heroesRemove
hero = ReturnOneHero(c, bson.M{"alias": "Doctor Strange"})
log.Println("Is Hero empty?", hero == Hero{ })

For last, let's imagine that Hawkeye changed his mind and now wants to sign the Accords. So let's make de UpdateHero method.

func UpdateHero(client *mongo.Client, updatedData bson.M, filter bson.M) int64 {
    collection := client.Database("civilact").Collection("heroes")
    atualizacao := bson.D{ {Key: "$set", Value: updatedData} }
    updatedResult, err := collection.UpdateOne(context.TODO(), filter, atualizacao)
    if err != nil {
        log.Fatal("Error on updating one Hero", err)
    }
    return updatedResult.ModifiedCount
}

That's it! The regular CRUD Operation was covered and our Heroes can decide their fate. All the code for these examples is available here and this tutorial was also posted at my blog. Here is the Driver's oficial repo and oficial docs

Feel free to get in touch for any question, suggestion or mistake that i made.

Did you like this article?

Eduardo Henrique da Silva Freitas

See other articles by Eduardo

Related jobs

See all

Title

The company

  • Remote

Title

The company

  • Remote

Title

The company

  • Remote

Title

The company

  • Remote

Related articles

JavaScript Functional Style Made Simple

JavaScript Functional Style Made Simple

Daniel Boros

12 Sep 2021

JavaScript Functional Style Made Simple

JavaScript Functional Style Made Simple

Daniel Boros

12 Sep 2021

WorksHub

CareersCompaniesSitemapFunctional WorksBlockchain WorksJavaScript WorksAI WorksGolang WorksJava WorksPython WorksRemote Works
hello@works-hub.com

Ground Floor, Verse Building, 18 Brunswick Place, London, N1 6DZ

108 E 16th Street, New York, NY 10003

Subscribe to our newsletter

Join over 111,000 others and get access to exclusive content, job opportunities and more!

© 2024 WorksHub

Privacy PolicyDeveloped by WorksHub