How to Manage MongoDB Client across Packages in Golang

Issue

I am currently starting out with MongoDB on GoLang. My current use case is this.

I wish to initialize connection to my MongoDB Database in a particular package and use the returned client across several other local packages. Here is what I have tried,

I have initialized the connection to MongoDB inside a package called dataLayer as below

package dataLayer

import (
    "context"
    "log"
    "time"

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

func InitDataLayer() {
    ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
    defer cancel()
    client, err := mongo.Connect(ctx, options.Client().ApplyURI(credentials.MONGO_DB_ATLAS_URI))
    if err != nil {
        log.Fatal(err)
    } else {
        log.Println("Connected to Database")
    }
}

Now if I wish to use the returned client in other packages, is it production safe to keep on calling initDataLayer over and over again to get back a client?

Thanks alot.

Solution

You don’t have to call InitDataLayer over and over again. You need to create only one client, you can use the same client to connect to Mongo DB from various places.

Mongo client internally maintains a pool of connections, so you don’t have to create this client again and again.

It’s a good design to store this client as the struct field and keep reusing the same.

Edit:

Create Connection

package dataLayer

import (
    "context"
    "log"
    "time"

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

func InitDataLayer()(*mongo.Client) {
    ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
    defer cancel()
    client, err := mongo.Connect(ctx, options.Client().ApplyURI(credentials.MONGO_DB_ATLAS_URI))
    if err != nil {
        log.Fatal(err)
    } else {
        log.Println("Connected to Database")
    }
    return client
}

main.go,

Close connection at the end of usage, otherwise connection would be leaked.

func main(){
   //...
   client = dataLayer.InitDataLayer()
   defer client.Disconnect(context.Background())
   ...
}

Repository/DAL, store client in Repository struct

Interface

type BookRepository interface {
   FindById( ctx context.Context, id int) (*Book, error)
}

Repository Implementation that store client in struct

type bookRepository struct {
  client *mongo.Client
}

func (r *bookRepository) FindById( ctx context.Context, id int) (*Book, error) {
  var book  Book
  err := r.client.DefaultDatabase().Collection("books").FindOne(ctx, bson.M{"_id": id }).Decode(&book)
  
  if err == mongo.ErrNoDocuments {
    return nil, nil
  }
  if err != nil  {
     return nil, err
  }
  return &book, nil
}

Answered By – sonus21

Answer Checked By – Jay B. (GoLangFix Admin)

Leave a Reply

Your email address will not be published.