MongoDB
MongoDB はドキュメントデータベースで、基本的なデータ単位はドキュメントです。保存フォーマットは BSON(Binary JSON)で、JSON に似た構造です。緩やかな構造により異なるタイプのデータを保存でき、リレーショナルデータベースと比較してより柔軟です。また、スクリプト言語として js を使用し、スクリプトを通じて組み合わせ操作を完了できます。この記事では主に Go で公式 mongo ドライバーを使用して mongodb データベースを操作する方法を紹介し、mongodb チュートリアルではありません。もし mongo の基礎知識がない場合は、まず自行で理解と学習を行ってください。
mongodb ドキュメント:Introduction to MongoDB — MongoDB Manual
ドライバー
Go に関するライブラリは少なく、早期にはコミュニティがメンテナンスするライブラリもありましたが、後にメンテナンスが停止しました。ただし、公式の mongo ドライバーライブラリはすでに十分に使用に足ります。
オープンソースリポジトリ:mongodb/mongo-go-driver: The Official Golang driver for MongoDB (github.com)
ドキュメントアドレス:mongodb/mongo-go-driver: The Official Golang driver for MongoDB (github.com)
インストール
依存関係をダウンロードする場合は、以下のアドレスを使用します。
$ go get go.mongodb.org/mongo-driver/mongo接続
以下は mongo クライアントとサーバーが接続を確立するシンプルな例です。
package main
import (
"context"
"fmt"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
"go.mongodb.org/mongo-driver/mongo/readpref"
"log"
)
func main() {
ctx := context.Background()
// URI を使用して接続を確立
client, err := mongo.Connect(ctx, options.Client().ApplyURI("mongodb://admin:123456@192.168.48.138:27017/"))
if err != nil {
log.Panicln(err)
}
// 接続を閉じる
defer client.Disconnect(ctx)
// ping テストで接続が利用可能か確認
fmt.Println(client.Ping(ctx, readpref.Primary()))
}bson
Go 内の mongodb は以下の数種類のタイプを使用してデータベース内のドキュメントをマッピングします。bson/bson.go に位置しています。
// BSON ドキュメントの順序付き表現
type D = primitive.D
// 鍵値のペア、BSON ドキュメントの順序付き表現の基本単位
type E = primitive.E
// BSON ドキュメントの順序なし表現
type M = primitive.M
// BSON データの順序付き表現
type A = primitive.Aそれらの実際のタイプは以下の通りです。
// BSON ドキュメントの順序付き表現
type D []E
// 鍵値のペア、BSON ドキュメントの順序付き表現の基本単位
type E struct {
Key string
Value interface{}
}
// BSON ドキュメントの順序なし表現
type M map[string]interface{}
// BSON データの順序付き表現
type A []interface{}上記の数種類のタイプを通じて、クエリ SQL を構築することも、データをマッピングすることもできます。
TIP
ドライバー examples ディレクトリには相当数の使用例があり、公式が上記の 4 つのタイプの使用方法を非常に詳細にデモンストレーションしています。
ドキュメントのクエリ
まず user データベースを作成し、users コレクションに以下のデータを挿入します。
> use user
> db.users.insertMany([
{
name: "mike",
age: 12,
},
{
name: "jenny",
age: 14,
},
{
name: "jack",
age: 18,
address: "usa"
}
])単一クエリ
type User struct {
Name string `bson:"name"`
Age int `bson:"age"`
Address string `bson:"address"`
}
var user User
result := client.Database("user"). // データベースを選択
Collection("users"). // コレクションを選択
FindOne(ctx, bson.D{{"address", "usa"}}) // 过滤条件
// 逆シリアライズ
if err := result.Decode(&user); err != nil {
log.Panicln(err)
}
fmt.Printf("%+v\n", user)上記のクエリコードは以下と同等です。
db.users.findOne({
address: "usa"
})出力結果
{Name:jack Age:18 Address:usa}複数クエリ
type User struct {
Name string `bson:"name"`
Age int `bson:"age"`
Address string `bson:"address"`
}
var users []User
cursor, err := client.Database("user"). // データベースを選択
Collection("users"). // コレクションを選択
Find(ctx, bson.D{}) // 过滤条件
if err != nil {
log.Panicln(err)
}
if err := cursor.All(ctx, &users); err != nil {
log.Panicln(err)
}
fmt.Printf("%+v\n", users)以下と同等です。
db.users.find({})出力
[{Name:jack Age:18 Address:usa} {Name:mike Age:12 Address:} {Name:jenny Age:14 Address:}]クエリ条件を構築する際、options を使用することもできます。
type User struct {
Name string `bson:"name"`
Age int `bson:"age"`
Address string `bson:"address"`
}
var users []User
find := options.Find()
find.SetSort(bson.M{"age": 1})
find.SetLimit(1)
cursor, err := client.Database("user"). // データベースを選択
Collection("users"). // コレクションを選択
Find(ctx, bson.D{}, find) // 过滤条件
if err != nil {
log.Panicln(err)
}
if err := cursor.All(ctx, &users); err != nil {
log.Panicln(err)
}
fmt.Printf("%+v\n", users)以下と同等です。
db.users.find({}).sort({age:1}).limit(1)出力
[{Name:mike Age:12 Address:}]ドキュメントの作成
以下はドキュメントを 1 つ作成する例です。
one, err := client.Database("user").Collection("users").InsertOne(ctx, User{
Name: "lili",
Age: 20,
Address: "china",
})
if err != nil {
log.Panicln(err)
}
fmt.Println(one.InsertedID)作成に成功すると、ドキュメントの ObjectID が返されます。
ObjectID("64c60fa01e2548d9e4de6cf4")以下は複数のドキュメントを作成する例です。
users := []any{User{
Name: "john",
Age: 10,
Address: "usa",
}, User{
Name: "pop",
Age: 30,
Address: "uk",
}}
one, err := client.Database("user").Collection("users").InsertMany(ctx, users)
if err != nil {
log.Panicln(err)
}
fmt.Println(one.InsertedIDs)作成に成功すると、一組の ObjectID が返されます。
[ObjectID("64c610d5aec2618d6ca0b515") ObjectID("64c610d5aec2618d6ca0b516")]上記の 2 つのコードは db.users.insertOne と db.users.insertMany と同等です。
ドキュメントの更新
以下は単一のドキュメントを更新する例で、名前が lili の人を mark に改名します。
upres, err := client.Database("user").Collection("users").UpdateOne(ctx, bson.D{
{"name", "mark"},
},
bson.D{
{"$set", bson.D{
{"name", "lili"},
}},
})
if err != nil {
log.Panicln(err)
}
fmt.Printf("%+v", upres)以下と同等です。
db.users.updateOne({
name: "lili"
}, {
$set: {
name: "mark"
},
})出力
&{MatchedCount:1 ModifiedCount:1 UpsertedCount:0 UpsertedID:<nil>}以下は複数のドキュメントを更新する例で、年齢が 10 の人のアドレスを cn に更新します。
upres, err := client.Database("user").Collection("users").UpdateMany(ctx, bson.D{
{"age", 10},
},
bson.D{
{"$set", bson.D{
{"address", "cn"},
}},
})
if err != nil {
log.Panicln(err)
}
fmt.Printf("%+v", upres)Update を使用する以外に、mongo は Replace も提供しています。両者の違いは、前者はドキュメントフィールドを更新し、後者はドキュメントを直接置換することです。例えば以下のコードでは、もはやオペレーターは必要ありません。
upres, err := client.Database("user").Collection("users").ReplaceOne(ctx, bson.D{
{"age", 10},
},
bson.D{
{"address", "cn"},
})
if err != nil {
log.Panicln(err)
}
fmt.Printf("%+v", upres)同時に mongo は FindOneAndUpdate と FindOneAndReplace を提供して、ドキュメントを取得し更新します。以下の通りです。
res := client.Database("user").Collection("users").FindOneAndReplace(ctx, bson.D{
{"address", "cn"},
},
bson.D{
{"address", "uk"},
})
if err := res.Err(); err != nil {
log.Panicln(err)
}
var user User
res.Decode(&user)
fmt.Printf("%+v", user)出力
Name: Age:0 Address:cn}この操作はドキュメントをクエリしてから修正します。
ドキュメントの削除
以下は 1 つのドキュメントを削除する例です。
result, err := client.Database("user").Collection("users").DeleteOne(ctx, bson.D{
{"name", "jack"},
})
if err != nil {
log.Panicln(err)
}
fmt.Println(result.DeletedCount)以下は複数のドキュメントを削除する例です。
result, err := client.Database("user").Collection("users").DeleteMany(ctx, bson.D{
{"age", "10"},
})
if err != nil {
log.Panicln(err)
}
fmt.Println(result.DeletedCount)集計
集計操作には mongo.Pipeline タイプを使用します。その本質は []bson.D です。
type Pipeline []bson.Dpipline := mongo.Pipeline{
{
{"$match", bson.D{
{"address", "uk"},
}},
},
{
{"$sort", bson.D{
{"age", 1},
}},
},
}
aggregate, err := client.Database("user").Collection("users").Aggregate(ctx, pipline)
if err != nil {
log.Panicln(err)
}
var users []User
if err := aggregate.All(ctx, &users); err != nil {
log.Panicln(err)
}
log.Println(users)出力
[{lili 20 uk} {kak 30 uk}]この集計操作は、address が uk のすべてのユーザーをマッチし、その後年齢でソートします。
