Как повторно использовать подключение MongoDB в Go - PullRequest
1 голос
/ 13 октября 2019

Я бы хотел подключить свой сервер, написанный на Go, к MongoDB, но я не уверен, как это сделать эффективно. Несколько примеров, которые я нашел, реализовали это, как показано ниже.

libs / mongodb / client.go

package mongodb

import (
    "context"
    "log"
    "project/keys"

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

func GetClient() *mongo.Database {
    client, err := mongo.Connect(
        context.Background(),
        options.Client().ApplyURI(keys.GetKeys().MONGO_URI),
    )

    if err != nil {
        log.Fatal(err)
    }

    return client.Database(keys.GetKeys().MONGO_DB_NAME)
}

services / user / findOne.go

package userservices

import (
    "context"
    "log"
    "project/libs/mongodb"
    "project/models"

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

func FindOne(filter bson.M) (models.User, error) {
    var user models.User

    collection := mongodb.GetClient().Collection("users")
    result := collection.FindOne(context.TODO(), filter)

    if result.Err() != nil {
        return user, result.Err()
    }

    if err := result.Decode(&user); err != nil {
        log.Println("Failed to decode user with error:", err)
        return user, err
    }

    return user, nil
}

Функция GetClient возвращает экземпляр базы данных, который затем используется в приложении. Кажется, это работает, но мне интересно, действительно ли это наилучшая практика, поскольку создается впечатление, что создается новое соединение каждый раз, когда запрашивается новый клиент, как показано во втором фрагменте кода, или это предположение неверно? Я также подумал о преобразовании GetClient в одноэлементный файл, который всегда возвращает один и тот же экземпляр базы данных, но как в этом случае будет обрабатываться потерянное соединение? Спасибо

1 Ответ

1 голос
/ 13 октября 2019

Я делаю это так. Сделайте это один раз при запуске службы, а затем передайте объект MongoDatastore в оркестратор, уровни обслуживания и уровни хранилища. Я использую драйвер "github.com/mongodb/mongo-go-driver/mongo" для Монго. Я думаю, что это внутренне контролирует и перерабатывает простаивающие соединения. Следовательно, нам не нужно беспокоиться о разрыве соединений, если ссылка на объект mongo.Client не потеряна.


const CONNECTED = "Successfully connected to database: %v"

type MongoDatastore struct {
    db      *mongo.Database
    Session *mongo.Client
    logger  *logrus.Logger
}

func NewDatastore(config config.GeneralConfig, logger *logrus.Logger) *MongoDatastore {

    var mongoDataStore *MongoDatastore
    db, session := connect(config, logger)
    if db != nil && session != nil {

        // log statements here as well

        mongoDataStore = new(MongoDatastore)
        mongoDataStore.db = db
        mongoDataStore.logger = logger
        mongoDataStore.Session = session
        return mongoDataStore
    }

    logger.Fatalf("Failed to connect to database: %v", config.DatabaseName)

    return nil
}

func connect(generalConfig config.GeneralConfig, logger *logrus.Logger) (a *mongo.Database, b *mongo.Client) {
    var connectOnce sync.Once
    var db *mongo.Database
    var session *mongo.Client
    connectOnce.Do(func() {
        db, session = connectToMongo(generalConfig, logger)
    })

    return db, session
}

func connectToMongo(generalConfig config.GeneralConfig, logger *logrus.Logger) (a *mongo.Database, b *mongo.Client) {

    var err error
    session, err := mongo.NewClient(generalConfig.DatabaseHost)
    if err != nil {
        logger.Fatal(err)
    }
    session.Connect(context.TODO())
    if err != nil {
        logger.Fatal(err)
    }

    var DB = session.Database(generalConfig.DatabaseName)
    logger.Info(CONNECTED, generalConfig.DatabaseName)

    return DB, session
}

Теперь вы можете создать свой репозиторий, как показано ниже: -

type TestRepository interface{
    Find(ctx context.Context, filters interface{}) []Document, error
}

type testRepository struct {
    store      *datastore.MongoDatastore
}

func (r *testRepository) Find(ctx context.Context , filters interface{}) []Document, error{
    cur, err := r.store.GetCollection("some_collection_name").Find(ctx, filters)
    if err != nil {
        return nil, err
    }
    defer cur.Close(ctx)
    var result = make([]models.Document, 0)
    for cur.Next(ctx) {
        var currDoc models.Document
        err := cur.Decode(&currDoc)
        if err != nil {
            //log here
            continue
        }
        result = append(result, currDoc)
    }
    return result, err
}

...