GogoDBのセットアップ方法


これを苦労していくつかの異なるリソースを組み合わせた後、私は次回のリファレンスガイドを書いた.それを共有する私の望みは、それが他の誰かを助けるということです.
免責事項:私はまだGogoDBを使用して比較的新しいので、これのいずれかの保証は最良の方法です.私は、それが私のために働くということを知っています.私は喜んで提案を開いている!

クイックスタート
コードに直接ジャンプしたいなら、githubにレポを設定します.https://github.com/imjoshellis/mongo-go-skeleton

必要条件
このガイドでは、基本をスキップします.私は、あなたが接続する準備ができているMongoDBのインスタンスを持っていると仮定します、そして、あなたはどのようにGoプロジェクトをセットアップするかを知っていますgo mod init .
私はスペースを節約するためにスニペットに輸入品を隠していますGitHub repo 完全なインポート情報を持つファイル.

ユーザーエンティティ
私たちは、これがどこにあるかについて見ることができるように、モデルから始めます.私は、GogoDBを扱う最も簡単な方法であることを構造体に注釈をつけました.ID、ユーザ名、メールを持つ単純なユーザータイプを作成したいと思います.あなたはそのようなタイプを宣言するでしょう.
BGOタグは重要なので、MOGOドライバはデータを関連付ける方法を理解することができます.JSONタグはこのプロジェクトでは消費されません.しかし、JSONを送信するAPIのコンテキストでこれを使用する可能性があるので、JSONとBSONタグの両方が一緒にどのように見えるかを見ることができます.
// src/entities/user.go
type User struct {
 ID       primitive.ObjectID `bson:"_id, omitempty" json:"id"`
 Username string             `bson:"username" json:"username"`
 Email    string             `bson:"email" json:"email"`
}
私たちは、後でユーザーを書いて、読むために、ここで2つの機能を加えます.

データベースへの接続
私の場合は、データの別のパッケージを作成することを選びました.スペシャルを使用しますinit 機能は、mongoクライアントを取得し、最初の時間をインポートインポートします.
ここでの焦点はMongoDBを取得し、ASPを実行しているので、我々は直接DBでの作業をしますmain.go , でも、普通はapp.go ルート/コントローラで.
DBファイルの構築を始めましょう.Full file on GitHub
注:いくつかの慣例はthis fantastic guide
まず、私はアプリケーションの他の部分にMongoクライアントとコレクションを公開することを選択しました
// src/data/users.db.go
var (
 Client     *mongo.Client
 Collection *mongo.Collection
)
データベース接続情報の環境変数を使いますので、いくつかの定数を設定しましょう.
// src/data/users.db.go
type key string

const (
 hostKey     = key("hostKey")
 usernameKey = key("usernameKey")
 passwordKey = key("passwordKey")
 databaseKey = key("databaseKey")
)
次に、私たちはinit 関数.ここでも、これはパッケージが最初にインポートされたときに実行される特別な名前付き関数です.
// src/data/users.db.go
func init() {
 var err error
 ctx := context.Background()
 ctx, cancel := context.WithTimeout(ctx, 2*time.Second)
 defer cancel()
 ctx = context.WithValue(ctx, hostKey, os.Getenv("MONGO_HOST"))
 ctx = context.WithValue(ctx, usernameKey, os.Getenv("MONGO_USERNAME"))
 ctx = context.WithValue(ctx, passwordKey, os.Getenv("MONGO_PASSWORD"))
 ctx = context.WithValue(ctx, databaseKey, os.Getenv("MONGO_DATABASE"))
 db, err := configDB(ctx)
 if err != nil {
  log.Fatalf("Database configuration failed: %v", err)
 }
 Collection = db.Collection("users") // Change me!
 log.Info("Successfully connected to MongoDB")
}
の主な目的init 関数は環境変数を取得し、コンテキストに設定する.その後、呼び出しを試みるconfigDB , これは実際にエラーチェックを行うDB接続を作成し、成功するとデータベースを返します.データベース名をカスタマイズします.
// src/data/users.db.go
func configDB(ctx context.Context) (*mongo.Database, error) {
 uri := fmt.Sprintf(`mongodb://%s:%s@%s/%s`,
  ctx.Value(usernameKey).(string),
  ctx.Value(passwordKey).(string),
  ctx.Value(hostKey).(string),
  ctx.Value(databaseKey).(string),
 )
 Client, err := mongo.NewClient(options.Client().ApplyURI(uri))
 if err != nil {
  return nil, fmt.Errorf("couldn't connect to mongo: %v", err)
 }
 err = Client.Connect(ctx)
 if err != nil {
  return nil, fmt.Errorf("client couldn't connect with context: %v", err)
 }
 db := Client.Database("appName") // Change me!
 return db, nil
}
インザバックinit また、開発用の一時的な関数も追加しました.最初のコレクションは、毎回ワイプinit が実行されます.明らかな理由のために、あなたは生産でこれを望みません:
// src/data/users.db.go
func init() {
// ...
 _, err = Collection.DeleteMany(ctx, bson.M{})
 if err != nil {
  log.Fatalf("Deleting users collection failed %v", err)
 }
 log.Warn("Users collection was reset! You probably don't want this to happen in production...")
// ...
}
次のことは、フィールドをどのようにユニークにするかの例です.
// src/data/users.db.go
func init() {
// ...
keys := []string{"email", "username"}
 for _, k := range keys {
  _, err = Collection.Indexes().CreateOne(
   ctx,
   mongo.IndexModel{
    Keys:    bson.D{{Key: k, Value: 1}},
    Options: options.Index().SetUnique(true),
   },
  )
  if err != nil {
   log.Fatalf("Failed to create unique index on %v: %v", k, err)
  }
  }
// ...
}
これにより、メールとユーザ名の両方がユニークな値になります.私は、それがMongoシェルでこれをするのがより良いと主張しました、そして、それはそれをする有効な方法です.私は、このようにして、特に開発中にエラーを避けるのは簡単です.

保存と取得
データベースの準備ができましたので、ユーザーエンティティファイルに戻り、MongoDBからの保存と読み取りのために2つの関数を作成しましょう.
// src/entities/user.go
func (u *User) Save() error {
 ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
 defer cancel()
 res, err := data.Collection.InsertOne(ctx, bson.M{"username": u.Username, "email": u.Email})
 if err != nil {
  log.Error(err)
  return fmt.Errorf("there was a problem saving to the db")
 }
 u.ID = res.InsertedID.(primitive.ObjectID)
 return nil
}
この部分はとても簡単です.コンテキストを取得し、InsertOne() ユーザを挿入し、ID の結果に基づくユーザのフィールドInsertOne() .
ここではGet() 機能
// src/entities/user.go
func (u *User) Get() error {
 ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
 defer cancel()
 filter := bson.D{{Key: "_id", Value: u.ID}}
 err := data.Collection.FindOne(ctx, filter).Decode(&u)
 if err != nil {
  return fmt.Errorf("user %s not found", u.ID.Hex())
 }
 return nil
}
ご覧のように、私たちは、ユーザーのIDに基づいてフィルタを設定して、次に呼び出しますFindOne() を収集します.The Decode() 関数は、成功した場合にユーザの空白を埋める.

メインでのテスト
今、通常、あなたはAPIルートとコントローラとすべてのそのジャズをセットアップするでしょう、しかし、これが働いているかどうかすぐにテストするために、私はセットアップしましたmain() ユーザーを作成して保存し、データベースに問い合わせます.私は、MongoDBへの接続が十分に長い間開いていることを確認するためにHTTPサーバを作るために繊維を使用しています.
// src/main.go
func main() {
 var user entities.User
 var err error
 user.Username = "imjoshellis"
 user.Email = "[email protected]"
 if user.ID == primitive.NilObjectID {
  log.Info("User has nil ObjectID. Attempting to save...")
 }
 err = user.Save()
 if err != nil {
  log.Fatal("Error reading user from db: %v", err)
 }
 if user.ID != primitive.NilObjectID {
  log.Info("User has a generated ObjectID. Save was successful.")
 }

 var readUser entities.User
 readUser.ID = user.ID
 if readUser.Email == "" {
  log.Info("New user entity created with matching ID. Attempting to read...")
 }
 err = readUser.Get()
 if err != nil {
  log.Fatal("Error reading user from db: %v", err)
 }
 if readUser.Email == user.Email {
  log.Info("New user has the same email as original. Read was successful.")
 }

 defer func() {
  log.Println("Disconnecting from MongoDB...")
  ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
  defer cancel()
  if err := data.Client.Disconnect(ctx); err != nil {
   log.Fatal(err)
  }
 }()

 app := fiber.New()
 log.Fatal(app.Listen("localhost:8080"))
}

メイン変数の実行
最後に、あなたが実行するときに、正しい変数を含めるようにしたいと思うでしょうgo run main.go .
私の場合は以下のようになります.
MONGO_HOST="localhost:27017" MONGO_USERNAME=myUserAdmin MONGO_PASSWORD=admin go run src/main.go
すべてがうまくいくなら、ログの束を見なければなりません、そして、サーバーが稼働していると言っているファイバーからのメッセージが続きます:
WARN[0000] Users collection was reset! You probably don't want this to happen in production...
INFO[0000] Successfully connected to MongoDB
INFO[0000] User has nil ObjectID. Attempting to save...
INFO[0000] User has a generated ObjectID. Save was successful.
INFO[0000] New user entity created with matching ID. Attempting to read...
INFO[0000] New user has the same email as original. Read was successful.

結論
それだ!もちろん、APIエンドポイント、更新/削除メソッド、より多くのエンティティなどを含む多くのより多くの機能を追加する必要があります.しかし、うまくいけば、これはMongoDBとGoを始めるのを助けました!