Querier

GoでMongoDBのデータ操作をマスターする

2023.07.12に公開 | 2023.07.12に更新

Querier運営

@querier_io@querierinc

「Querier(クエリア)」は社内向け管理画面を圧倒的な速さで、かつビジネスのスケールに合わせて柔軟に構築することができるローコードツールです。

管理画面の構築もWeb上で完結
エンジニアのためのローコードツール

Querierについて詳しく見る

Go言語とMongoDBは、高性能なバックエンドシステムを構築する際の強力な組み合わせと言えます。

MongoDBは、スケーラビリティと性能を兼ね備えたNoSQLデータベースであり、Go言語は並行処理に優れ、シンプルなコードを書くことが可能です。

今回の記事では、Go言語を使ってMongoDBのデータ操作を学びましょう。

セットアップ

まず、Go言語でMongoDBを操作するために必要なライブラリをインストールします。ここでは公式のMongoDBドライバーを使用します。

go get go.mongodb.org/mongo-driver/mongo

次に、MongoDBクライアントを生成します。

詳細な設定方法は公式ドキュメントを参照してください。

package main


import (
    "context"
    "fmt"
    "log"

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

func main() {
    clientOptions := options.Client().ApplyURI("mongodb://localhost:27017")
    client, err := mongo.Connect(context.TODO(), clientOptions)
    if err != nil {
        log.Fatal(err)
    }

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

    fmt.Println("Connected to MongoDB!")
}

データの取得

FindOne

単一のドキュメントを取得するにはfindOneメソッドを使用します。

詳細な設定方法は公式ドキュメントを参照してください。

var result bson.M
err := collection.FindOne(context.TODO(), bson.M{}).Decode(&result)
if err != nil {
    log.Fatal(err)
}

fmt.Println(result)

Find

複数のドキュメントを取得するにはfindメソッドを使用します。

詳細な設定方法は公式ドキュメントを参照してください。

findOptions := options.Find()
var results []*bson.M
cur, err := collection.Find(context.TODO(), bson.M{}, findOptions)
if err != nil {
    log.Fatal(err)
}

for cur.Next(context.TODO()) {
    var elem bson.M
    err := cur.Decode(&elem)
    if err != nil {
        log.Fatal(err)
    }
    results = append(results, &elem)
}

if err := cur.Err(); err != nil {
    log.Fatal(err)
}

cur.Close(context.TODO())

ページングを実装する

結果のドキュメント数が多い場合、SkipLimitを使用してページングを実装することができます。

詳細な設定方法は公式ドキュメントを参照してください。

findOptions.SetLimit(5)
findOptions.SetSkip(10)

データの追加

ここでは、Goの構造体を使ってデータを追加していきます。

MongoDBのドライバでは、「bson」タグを使って構造体のフィールドとMongoDBのドキュメントフィールドのマッピングを行います。

これにより、構造体のフィールド名とドキュメントのフィールド名が異なる場合でも、正しくマッピングすることができます。

InsertOne

単一のドキュメントを追加するにはInsertOneメソッドを使用します。

詳細な設定方法は公式ドキュメントを参照してください。

type User struct {
    Name string `bson:"name"`
    Age  int    `bson:"age"`
}

document := User{
    Name: "John Doe",
    Age25,
}
insertResult, err := collection.InsertOne(context.TODO(), document)
if err != nil {
    log.Fatal(err)
}

fmt.Println("Inserted a Single Document: ", insertResult.InsertedID)

InsertMany

複数のドキュメントを追加するにはInsertManyメソッドを使用します。

詳細な設定方法は公式ドキュメントを参照してください。

documents := []interface{}{
    User{Name: "John Doe", Age: 25},
    User{Name: "Jane Doe", Age: 28},
}

insertManyResult, err := collection.InsertMany(context.TODO(), documents)
if err != nil {
    log.Fatal(err)
}

fmt.Println("Inserted multiple documents: ", insertManyResult.InsertedIDs)

データの更新

UpdateOne

単一のドキュメントを更新するにはUpdateOneメソッドを使用します。

詳細な設定方法は公式ドキュメントを参照してください。

filter := bson.D{{"name", "John Doe"}}
update := bson.D{
    {"$set", bson.D{
        {"age", 26},
    }},
}

updateResult, err := collection.UpdateOne(context.TODO(), filter, update)
if err != nil {
    log.Fatal(err)
}

fmt.Printf("Matched %v documents and updated %v documents.\n", updateResult.MatchedCount, updateResult.ModifiedCount)

UpdateMany

複数のドキュメントを更新するにはUpdateManyメソッドを使用します。

詳細な設定方法は公式ドキュメントを参照してください。

filter := bson.M{"age": bson.M{"$gt": 25}}
update := bson.D{
    {"$inc", bson.D{
        {"age", 1},
    }},
}

updateResult, err := collection.UpdateMany(context.TODO(), filter, update)
if err != nil {
    log.Fatal(err)
}

fmt.Printf("Matched %v documents and updated %v documents.\n", updateResult.MatchedCount, updateResult.ModifiedCount)

FindOneAndUpdate

条件にマッチしたドキュメントを検索し、最初のドキュメントを更新するにはfindOneAndUpdateメソッドを使用します。

詳細な設定方法は公式ドキュメントを参照してください。

opts := options.FindOneAndUpdate().SetReturnDocument(options.After)
filter := bson.D{{"name", "John Doe"}}
update := bson.D{{"$inc", bson.D{{"age", 1}}}}

var updatedDocument bson.M
err := collection.FindOneAndUpdate(context.TODO(), filter, update, opts).Decode(&updatedDocument)
if err != nil {
    log.Fatal(err)
}

fmt.Printf("Updated document %v\n", updatedDocument)

データの削除

DeleteOne

単一のドキュメントを削除するにはDeleteOneメソッドを使用します。

詳細な設定方法は公式ドキュメントを参照してください。

deleteFilter := bson.D{{"name", "John Doe"}}
deleteResult, err := collection.DeleteOne(context.TODO(), deleteFilter)
if err != nil {
    log.Fatal(err)
}

fmt.Printf("Deleted %v documents in the trainers collection\n", deleteResult.DeletedCount)

DeleteMany

複数のドキュメントを削除するにはDeleteManyメソッドを使用します。

詳細な設定方法は公式ドキュメントを参照してください。

filter := bson.M{"age": bson.M{"$gt": 25}}
deleteResult, err := collection.DeleteMany(context.TODO(), filter)
if err != nil {
    log.Fatal(err)
}

fmt.Printf("Deleted %v documents in the trainers collection\n", deleteResult.DeletedCount)

トランザクション処理

MongoDB 4.0以降、複数の操作を一つのトランザクションとして扱うことができます。

詳細な設定方法は公式ドキュメントを参照してください。

session, err := client.StartSession()
if err != nil {
    log.Fatal(err)
}
defer session.EndSession(context.TODO())

callback := func(sessionContext mongo.SessionContext) (interface{}, error) {
    // perform operations....

    return nil, nil
}

_, err = session.WithTransaction(context.TODO(), callback)
if err != nil {
    log.Fatal(err)
}

bson.Dとbson.Mとは、違い

MongoDBドライバーで提供されているbson.Dbson.MはどちらもBSONドキュメントを表すための型ですが、それぞれが異なる目的と利用シーンを持っています。

bson.D

bson.D順序を保持したドキュメントを表します。bson.D[]primitive.Eのエイリアスで、primitive.Eはフィールド名と値をペアで持つ構造体です。

これにより、フィールドの順序が重要な操作(例えば、アップデートの操作でフィールドの削除と追加を順序を保持して行いたい場合)にbson.Dを使用します。

bson.D{{"name", "John Doe"}, {"age", 30}}

bson.M

bson.M順序を保持しないマップを表します。Goの標準マップのエイリアスで、map[string]interface{}型となっています。

フィールドの順序が問題とならない場合(例えば、クエリフィルタや結果の取得)にはbson.Mを使用します。

bson.M{"name": "John Doe", "age": 30}

さいごに

以上がGo言語を使ってMongoDBのデータ操作を行う方法についての解説です。

この記事があなたのMongoDBとGo言語に対する理解を深める一助となれば幸いです。

「Querier(クエリア)」は社内向け管理画面を圧倒的な速さで、かつビジネスのスケールに合わせて柔軟に構築することができるローコードツールです。

最新の記事

2〜3ヶ月と見積もっていた開発期間を、クエリアを導入することでわずか1週間に短縮できました

2012年5月創業のフルカイテン株式会社。 「在庫をフル回転させる」をコンセプトに、機械学習を駆使したSaaS『FULL KAITEN』を提供し、在庫問題の解決に取り組む。

more

管理画面の構築もWeb上で完結
エンジニアのためのローコードツール

Querierについて詳しく見る