17.1Go语言操作MongoDB

驱动安装

bash 复制代码
go get go.mongodb.org/mongo-driver/mongo

基础连接示例

go 复制代码
package main

import (
    "context"
    "fmt"
    "log"
    "time"
    
    "go.mongodb.org/mongo-driver/mongo"
    "go.mongodb.org/mongo-driver/mongo/options"
)

func main() {
    // 设置客户端选项
    clientOptions := options.Client().ApplyURI("mongodb://localhost:27017").SetConnectTimeout(10 * time.Second)

    // 连接MongoDB
    client, err := mongo.Connect(context.Background(), clientOptions)
    if err != nil {
        log.Fatal(err)
    }
    defer func() {
        if err = client.Disconnect(context.Background()); err != nil {
            log.Fatal(err)
        }
    }()

    fmt.Println("成功连接到MongoDB!")
}

标题数据库操作

  1. 创建数据库和集合
go 复制代码
db := client.Database("mydb")
usersColl := db.Collection("users")
  1. 文档定义(结构体)
go 复制代码
type User struct {
    ID       primitive.ObjectID `bson:"_id,omitempty" json:"id"`
    Username string             `bson:"username" json:"username"`
    Email    string             `bson:"email" json:"email"`
    CreatedAt time.Time        `bson:"createdAt" json:"created_at"`
}

CRUD操作

  1. 插入文档
go 复制代码
insertResult, err := usersColl.InsertOne(
    context.Background(),
    User{
        Username: "john_doe",
        Email:    "[email protected]",
        CreatedAt: time.Now(),
    },
)

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

fmt.Printf("插入ID: %v\n", insertResult.InsertedID)
  1. 查询文档
go 复制代码
filter := bson.D{{"username", "john_doe"}}
var results []User

cursor, err := usersColl.Find(context.Background(), filter)
if err != nil {
    log.Fatal(err)
}

defer cursor.Close(context.Background())

if err = cursor.All(context.Background(), &results); err != nil {
    log.Fatal(err)
}

fmt.Printf("找到%d个用户:\n", len(results))
for _, user := range results {
    fmt.Printf("- %s (%s)\n", user.Username, user.Email)
}
  1. 更新文档
go 复制代码
updateFilter := bson.D{{"username", "john_doe"}}
update := bson.D{{"$set", bson.D{{"email", "[email protected]"}}}}

result, err := usersColl.UpdateOne(
    context.Background(),
    updateFilter,
    update,
)

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

fmt.Printf("匹配到%d个文档,更新%d个\n", result.MatchedCount, result.UpdatedCount)
  1. 删除文档
go 复制代码
deleteResult, err := usersColl.DeleteOne(
    context.Background(),
    bson.D{{"username", "john_doe"}},
)

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

fmt.Printf("删除%d个文档\n", deleteResult.DeletedCount)

聚合操作

go 复制代码
pipeline := mongo.Pipeline{
    {{"$match", bson.D{{"status", "active"}}}},
    {{"$group", bson.D{
        {"_id", bson.D{{"department", "$department"}}},
        {"total", bson.D{{"$sum", 1}}},
    }}},
}

var results []bson.M
cursor, err := usersColl.Aggregate(context.Background(), pipeline)
if err != nil {
    log.Fatal(err)
}

defer cursor.Close(context.Background())

if err = cursor.All(context.Background(), &results); err != nil {
    log.Fatal(err)
}

fmt.Println("部门用户统计:")
for _, doc := range results {
    fmt.Printf("%s: %d人\n", doc["_id"].(string), doc["total"].(int32))
}

事务处理

go 复制代码
session, err := client.StartSession()
if err != nil {
    log.Fatal(err)
}
defer session.EndSession(context.Background())

txOptions := options.Transaction().SetReadConcern(readconcern.Majority()).SetWriteConcern(writeconcern.Majority())

err = session.WithTransaction(context.Background(), func(sessCtx mongo.SessionContext) error {
    // 在事务中执行多个操作
    _, err := usersColl.InsertOne(sessCtx, User{Username: "alice"})
    if err != nil {
        return err
    }

    _, err = ordersColl.InsertOne(sessCtx, Order{UserID: "alice", Total: 100})
    if err != nil {
        return err
    }

    return nil
}, txOptions)

if err != nil {
    log.Fatal("事务失败:", err)
} else {
    fmt.Println("事务成功")
}

高级功能

  1. 索引管理
go 复制代码
indexModel := mongo.IndexModel{
    Keys: bson.D{{"username", 1}},
}

_, err = usersColl.Indexes().CreateOne(
    context.Background(),
    indexModel,
)

if err != nil {
    log.Fatal(err)
}
fmt.Println("索引创建成功")
  1. 分页查询
go 复制代码
pageSize := 10
pageNumber := 2

filter := bson.D{}
sort := bson.D{{"createdAt", -1}}

optionsFind := options.Find().
    SetLimit(int64(pageSize)).
    SetSkip(int64((pageNumber-1)*pageSize)).
    SetSort(sort)

cursor, err := usersColl.Find(context.Background(), filter, optionsFind)
// 处理游标...

错误处理

go 复制代码
func safeMongoOp(ctx context.Context, op func() (interface{}, error)) (interface{}, error) {
    ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
    defer cancel()

    result, err := op()
    if err != nil {
        return nil, fmt.Errorf("mongo operation failed: %w", err)
    }
    return result, nil
}

连接池配置

go 复制代码
clientOptions := options.Client().
    ApplyURI("mongodb://localhost:27017").
    SetMaxPoolSize(100).
    SetMinPoolSize(10).
    SetConnectTimeout(10 * time.Second).
    SetSocketTimeout(30 * time.Second)

资源清理

go 复制代码
// 使用defer确保资源释放
cursor, err := collection.Find(ctx, filter)
if err != nil {
    // 处理错误
}

defer cursor.Close(ctx)

性能优化建议

  • 使用批量操作(InsertMany/UpdateMany)
  • 合理使用索引
  • 限制查询结果集大小
  • 使用投影(Projection)减少数据传输
  • 适当使用缓存机制

测试

go 复制代码
setupTestDB(t)
    
    // 测试插入
    user := User{Username: "test_user"}
    insertResult, _ := collection.InsertOne(context.Background(), user)
    
    // 测试查询
    filter := bson.D{{"username", "test_user"}}
    var foundUser User
    err := collection.FindOne(context.Background(), filter).Decode(&foundUser)
    
    // 清理测试数据
    _, _ = collection.DeleteOne(context.Background(), bson.D{{"_id", insertResult.InsertedID}})

简单完整例子

go 复制代码
package main 

import (
    "context"
    "fmt"
    "log"
    "time"
    
    "go.mongodb.org/mongo-driver/bson" 
    "go.mongodb.org/mongo-driver/mongo" 
    "go.mongodb.org/mongo-driver/mongo/options" 
)
// 定义数据结构体 
type User struct {
    Name  string `bson:"name"`
    Email string `bson:"email"`
    Age   int    `bson:"age"`
}
 
func main() {
    // 1. 连接 MongoDB 
    client, err := mongo.Connect(
        context.TODO(),
        options.Client().ApplyURI("mongodb://localhost:27017"),
    )
    if err != nil {
        log.Fatal("连接失败:", err)
    }
    defer client.Disconnect(context.TODO()) // 确保关闭连接 
 
    // 2. 选择数据库和集合 
    db := client.Database("testdb")
    collection := db.Collection("users")
 
    // 3. 插入文档 
    user := User{Name: "张三", Email: "[email protected]",  Age: 28}
    insertResult, err := collection.InsertOne(context.TODO(), user)
    if err != nil {
        log.Fatal("插入失败:", err)
    }
    fmt.Printf("插入ID: %v\n", insertResult.InsertedID)
 
    // 4. 查询文档 
    filter := bson.D{{"name", "张三"}}
    var result User 
    err = collection.FindOne(context.TODO(), filter).Decode(&result)
    if err != nil {
        log.Fatal("查询失败:", err)
    }
    fmt.Printf("查询结果: %+v\n", result)
 
    // 5. 更新文档 
    update := bson.D{{"$set", bson.D{{"age", 30}}}}
    updateResult, err := collection.UpdateOne(
        context.TODO(),
        filter,
        update,
    )
    if err != nil {
        log.Fatal("更新失败:", err)
    }
    fmt.Printf("更新数量: %d\n", updateResult.ModifiedCount)
 
    // 6. 删除文档 
    deleteResult, err := collection.DeleteOne(context.TODO(), filter)
    if err != nil {
        log.Fatal("删除失败:", err)
    }
    fmt.Printf("删除数量: %d\n", deleteResult.DeletedCount)
}```
相关推荐
Run_Teenage2 分钟前
我的创作纪念日
c语言·开发语言
青木川崎35 分钟前
java基础之windows电脑基础命令
java·开发语言·windows
癞皮狗不赖皮2 小时前
WEB攻防- PHP反序列化&属性权限特征&原生类 TIPS&字符串逃逸&CVE 绕过漏洞
开发语言·php
UpUpUp……2 小时前
C++继承与组合完结
开发语言·c++·笔记
淘小欣2 小时前
10分钟打造专属AI助手:用ms-swift实现自我认知微调
开发语言·人工智能·ai·swift·模型微调
搬砖工程师Cola3 小时前
<C#> 详细介绍.net 三种依赖注入:AddTransient、AddScoped、AddSingleton 的区别
开发语言·c#·.net
画个逗号给明天"6 小时前
C#从入门到精通(1)
开发语言·c#
JavaPub-rodert7 小时前
golang 的 goroutine 和 channel
开发语言·后端·golang
lly2024067 小时前
Matplotlib 柱形图
开发语言
_Matthew8 小时前
JavaScript |(四)正则表达式 | 尚硅谷JavaScript基础&实战
开发语言·javascript·正则表达式