Arvis
Arvis

Reputation: 43

How to properly disconnect MongoDB client

As far as I understand, you have to disconnect from MongoDB after you finish using it, but I'm not entirely sure how to do it right

var collection *mongo.Collection
var ctx = context.TODO()

func init() {
    clientOptions := options.Client().ApplyURI("mongodb://localhost:27017/")
    client, err := mongo.Connect(ctx, clientOptions)
    if err != nil {
        log.Fatal(err)
    }
    //defer client.Disconnect(ctx)

    err = client.Ping(ctx, nil)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println("Connected successfully")

    collection = client.Database("testDB").Collection("testCollection") //create DB
}

There is commented out function call defer client.Disconnect(ctx) Which would work fine if all code happens in main() function, but since defer gets called right after init() executes, DB in main() function is already disconnected.

So the question is - what would be the right way to approach this case?

Upvotes: 4

Views: 11342

Answers (1)

Cem Ikta
Cem Ikta

Reputation: 1450

Your application needs the connected MongoDB client in your all services or repositories and therefore it is easier, if you have separated MongoDB client connect and disconnect functions in application package. You don't need to connect MongoDB client, if your server is starting, you can connect first if your services or repositories need the MongoDB client connection.

// db.go
package application

import (
    "context"
    "fmt"
    "go.mongodb.org/mongo-driver/mongo"
    "go.mongodb.org/mongo-driver/mongo/options"
    "log"
    "os"
)

var client *mongo.Client

func ResolveClientDB() *mongo.Client {
    if client != nil {
        return client
    }

    var err error
    // TODO add to your .env.yml or .config.yml MONGODB_URI: mongodb://localhost:27017
    clientOptions := options.Client().ApplyURI(os.Getenv("MONGODB_URI"))
    client, err = mongo.Connect(context.Background(), clientOptions)
    if err != nil {
        log.Fatal(err)
    }

    // check the connection
    err = client.Ping(context.Background(), nil)
    if err != nil {
        log.Fatal(err)
    }

    // TODO optional you can log your connected MongoDB client
    return client
}

func CloseClientDB() {
    if client == nil {
        return
    }

    err := client.Disconnect(context.TODO())
    if err != nil {
        log.Fatal(err)
    }

    // TODO optional you can log your closed MongoDB client
    fmt.Println("Connection to MongoDB closed.")
}

In main:

func main() {
    // TODO add your main code here
    defer application.CloseClientDB()
}

In your repositories or services you can get now your MongoDB client easily:

// account_repository.go

// TODO add here your account repository interface
func (repository *accountRepository) getClient() *mongo.Client {
    if repository.client != nil {
        return repository.client
    }
    repository.client = application.ResolveClientDB()
    return repository.client
}

func (repository *accountRepository) FindOneByFilter(filter bson.D) (*model.Account, error) {
    var account *model.Account
    collection := repository.getClient().Database("yourDB").Collection("account")
    err := collection.FindOne(context.Background(), filter).Decode(&account)
    return account, err
}

Upvotes: 8

Related Questions