mongo-go-driverの接続処理を関数オブジェクトを活用して共通化してみる

2 min読了の目安(約1900字TECH技術記事

概要

GolangでMongoDBを使う時に入れるライブラリmongo-go-driverですが、RDBでベタでSQLを書くようなDBの接続処理を書かなければいけません。MongoDB.com公式Goドライバを使った基本操作の記事にあるように、コンテキストの生成・接続処理・deferによる切断処理、を書いていきその後にクエリを発行する形になります。
ただ、この一連の接続処理がクエリ毎に変わるわけではないので、どうにかして共通化してみようと考えてみて、実装の一例を書いてみます。なお、この記事はあくまで個人的に考えたものであるので、一般的にこの内容がベストであるかは定かではなく、あくまで参考までにして頂けると幸いです。

実装方針

  • クエリについては関数オブジェクト(関数の値化のことを関数オブジェクトと言うものとする)で別途定義して、共通の実行処理に渡します。Golangで関数オブジェクトを使う方法はGo言語 - 無名関数を参照のこと。
  • 共通のクエリ実行処理には、関数オブジェクトとコレクション名を渡します。
  • 共通のクエリ実行処理の返り値は[]bson.M型固定とする。もしfind文で結果のデコードが必要な場合は、受け取った先でデコードを行うものとします。

実装例

  • クエリの定義
querySample.go
func GetSample(param string) (sample.Result, error) {
	// 共通処理に渡す関数
	f := func(col *mongo.Collection) ([]bson.M, error) {
		findOptions := options.Find()
		findOptions.SetSort(bson.D{{Key: "date", Value: 1}})
		filter := bson.D{{Key: "word", Value: "param"}}
		cur, err := col.Find(context.Background(), filter, findOptions)
		if err != nil {
			return nil, err
		}
		var docs []bson.M
		for cur.Next(context.Background()) {
			var doc bson.M
			if err = cur.Decode(&doc); err != nil {
				return nil, err
			}
			docs = append(docs, doc)
		}
		return docs, nil
	}
	// 共通
	queryResult, err := util.ExecuteDbQuery(f, "sample_collection")
	if err != nil {
		return nil, err
	}
	// 以下デコード処理・・・
}
  • 実行処理
executeSample.go
func ExecuteDbQuery(queryFunc func(*mongo.Collection) ([]bson.M, error), colName string) ([]bson.M, error) {
	// MongoDBの接続設定
	ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second)
	defer cancel()
	c, _ := mongo.Connect(ctx, options.Client().ApplyURI(os.Getenv("DB_CONNECTION")))
	defer c.Disconnect(ctx)

	col := c.Database(os.Getenv("DB_NAME")).Collection(colName)
	// 関数の呼び出し結果を返す
	return queryFunc(col)
}