前言
在 Go
语言里使用 MongoDB
官方提供的 mongo-go-driver
库进行集合操作时,你是否感到结构体与 MongoDB
集合之间的映射,以及构建 BSON
数据这些操作极其繁琐?特别是在构建 BSON
数据时,各种字段、逗号和括号的排列组合是否让你觉得仿佛在进行一场复杂的拼图游戏?
如果你有同感,那么你并不孤单,我也是。因此我在想,有没有一个能让我丝滑,高效操作 MongoDB
的第三方库呢,遗憾的是,并没有找到符合我预期的库,索性我就自己动手开发了一个,这就是 go mongox
库的由来。
如果你也有类似我的这种感受,相信 go mongox
库能给你带来不一样的体验。
Go Mongox
go mongox
是一个基于泛型的库,扩展了 MongoDB
的官方库。通过泛型技术,它实现了结构体与 MongoDB
集合的绑定,旨在提供类型安全和简化的数据操作。
go mongox
还引入链式调用,让文档操作更流畅,并且提供了丰富的 BSON
构建器和内置函数,简化了 BSON
数据的构建。
此外,它还支持插件化编程和内置多种钩子函数,为数据库操作前后的自定义逻辑提供灵活性,增强了应用的可扩展性和可维护性。
仓库地址:https://github.com/chenmingyong0423/go-mongox
欢迎体验
go mongox
库,也期待您的贡献。如果您觉得这个库对您有帮助,请给它一个 Star 支持!
功能特性
- 泛型的
MongoDB
集合 - 支持
BSON
数据的构建 - 文档的
CRUD
操作 - 聚合操作
- 内置基本的
Model
结构体,自动化更新默认的field
字段 - 支持结构体
tag
校验 Hooks
- 支持插件化编程
安装
go get github.com/chenmingyong0423/go-mongox@latest
Collection 集合操作
基于泛型的 Collection 形态初始化
package main
import (
"context"
"fmt"
"github.com/chenmingyong0423/go-mongox"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
"go.mongodb.org/mongo-driver/mongo/readpref"
)
type User struct {
mongox.Model `bson:"inline"`
Name string `bson:"name"`
Age int `bson:"age"`
}
func main() {
// 你需要预先创建一个 *mongo.Collection 对象
mongoColl := newCollection()
// 使用 User 结构体作为泛型参数创建一个 collection
userColl := mongox.NewCollection[User](mongoColl)
fmt.Println(userColl != nil)
}
// 示例代码,不是最佳的创建方式
func newCollection() *mongo.Collection {
client, err := mongo.Connect(context.Background(), options.Client().ApplyURI("mongodb://localhost:27017").SetAuth(options.Credential{
Username: "test",
Password: "test",
AuthSource: "db-test",
}))
if err != nil {
panic(err)
}
err = client.Ping(context.Background(), readpref.Primary())
if err != nil {
panic(err)
}
collection := client.Database("db-test").Collection("test_post")
return collection
}
通过 mongox.NewCollection
函数,我们可以指定泛型参数并创建一个泛型的 Collection
对象。这样我们就可以使用 userColl
对象来操作 User
类型的文档了。
后面的操作将基于 userColl
对象进行举例。
Creator 创造器
通过 Creator()
方法获取一个新的泛型的创建器对象,即 Creator[T]
,通过 Creator[T]
的方法,我们能够执行相关的创建操作。
示例
// 插入单个文档
insertOneResult, err := userColl.Creator().InsertOne(context.Background(), &User{
Name: "陈明勇", Age: 18})
users := []*User{
{
Name: "Mingyong Chen", Age: 18},
{
Name: "cmy", Age: 18},
}
// 插入多个文档
insertManyResult, err := userColl.Creator().InsertMany(context.Background(), users)
InsertOne
和 InsertMany
方法与官方的 API
同名,前者用于插入单个文档,后者用于插入多个文档。如果我们需要设置 options
参数,可以将其作为这两个方法的第三个参数传递。
更多用法可前往官网文档 Creator 创造器 | go mongox 进行查看。
Finder 查询器
通过 Finder()
方法获取一个新的泛型的查询器对象,即 Finder[T]
。通过 Finder[T]
的方法,我们能够执行相关的查询操作。
示例
// 查询单个文档
post, err := userColl.Finder().Filter(query.Id(primitive.NewObjectID())).FindOne(context.Background())
// - 复杂条件查询
// -- 使用 query 包构建复杂的 bson
// -- bson.D{bson.E{Key:"name", Value:bson.D{bson.E{Key:"$eq", Value:"陈明勇"}}}, bson.E{Key:"age", Value:bson.D{bson.E{Key:"$eq", Value:18}}}}
post, err = userColl.Finder().
Filter(query.NewBuilder().Eq("name", "陈明勇").Eq("age", 18).Build()).
FindOne(context.Background())
// 查询多个文档
posts, err := userColl.Finder().
Filter(query.In("name", []string{
"陈明勇", "Mingyong Chen"}...)).
Find(context.Background())
FindOne
和 Find
方法与官方的 API
同名,前者用于查询单个文档,后者用于查询多个文档。我们可以通过 Filter
方法设置 查询条件,如果我们需要设置 options
参数,可以将其作为这两个方法的第二个参数传递。
对于简单的查询条件,我们可以使用 query
包提供的函数进行构建,例如 query.(id)
;对于复杂的查询条件,我们可以使用 query
包提供的 Builder
构建器进行构建。query
包的用法会在下面的内容进行详细地介绍。
更多用法可前往官网文档 Finder 查询器 | go mongox 进行查看。
Updater 更新器
通过 Updater()
方法获取一个新的泛型的更新器对象,即 Updater[T]
。通过 Updater[T]
的方法,我们能够执行相关的更新操作。
示例
// 更新单个文档
// 通过 update 包构建 bson 更新语句
updateResult, err := userColl.Updater().
Filter(query.Id(primitive.NewObjectID())).
Updates(update.Set("age", 19)).
UpdateOne(context.Background())
// 更新多个文档
updateResult, err = userColl.Updater().
Filter(query.In("name", []string{
"陈明勇", "Mingyong Chen"}...)).
Updates(update.Set("age", "19")).
UpdateMany(context.Background())
UpdateOne
和 UpdateMany
方法与官方的 API
同名,前者用于更新单个文档,后者用于更新多个文档。我们可以通过 Filter
方法设置 文档匹配的条件,如果我们需要设置 options
参数,可以将其作为这两个方法的第二个参数传递。
对于更新参数,我们可以使用 Updates
方法进行设置。该方法接收 bson
或 map
等合法的更新操作语句。上面的例子使用了 update
包里的 Set
对更新操作语句进行构建。
更多用法可前往官网文档 Updater 更新器 | go mongox 进行查看。
Deleter 删除器
通过 Deleter()
方法获取一个新的泛型的删除器对象,即 Deleter[T]
。通过 Deleter[T]
的方法,我们能够执行相关的删除操作。
示例
// 删除单个文档
deleteResult, err := userColl.Deleter().Filter(query.Id(primitive.NewObjectID())).DeleteOne(context.Background())
// 删除多个文档
deleteResult, err = userColl.Deleter().
Filter(query.In("name", "Mingyong Chen", "cmy")).
DeleteMany(context.Background())
DeleteOne
和 DeleteMany
方法与官方的 API
同名,前者用于删除单个文档,后者用于删除多个文档。我们可以通过 Filter
方法设置 文档匹配的条件。如果我们需要设置 options
参数,可以将其作为这两个方法的第二个参数传递。
更多用法可前往官网文档 Deleter 删除器 | go mongox 进行查看。
Aggregator 聚合器
通过 Aggregator()
获取一个新的泛型的聚合器对象,即 Aggregator[T any]
,通过 Aggregator[T any]
的方法,我们能够执行相关的聚合操作。
聚合器实现了三个方法:
Pipeline()
用于设置聚合管道。Aggregate()
用于执行聚合操作,返回的查询结果类型与T
一致。AggregateWithParse()
也是用于执行聚合操作,但使用场景不一样。当聚合结果的类型与T
不一致时,使用AggregateWithParse()
方法可以将结果解析到指定的对象里。
// 忽略年龄字段,只查询名字
users, err := userColl.Aggregator().
Pipeline(aggregation.NewStageBuilder().Project(bsonx.M("age", 0)).Build()).
Aggregate(context.Background())
// 字段重命名,聚合查询并解析结果
type RealUser struct {
mongox.Model `bson:"inline"`
RealName string `bson:"real_name"`
Age int `bson:"age"`
}
var results []*RealUser
err = userColl.Aggregator().
Pipeline(aggregation.NewStageBuilder().Project(
bsonx.NewD().Add("real_name", "$name").Add("age", 1).Build(),
).Build()).
AggregateWithParse(context.Background(), &results)
更多用法可前往官网文档 Aggregator 聚合器 | go mongox 进行查看。
BSON 数据构建
Go mongox
设计了多种不同类型的 BSON
构建器和函数,为我们开发者在不同场景下构建 BSON
数据提供了强大的支持。无论是数据查询、更新,还是执行复杂的聚合操作,开发者都可以在 bsonx
、query
和 update
以及 aggregation
专门的包中找到合适的构建器或函数。这些 BSON
构建器和函数不仅优化了代码的编写过程,还显著提高了开发效率,使得处理复杂的 BSON 数据变得既简单又高效。
bsonx 包
bsonx
提供提供了一系列便捷的函数和构建器去构建 BSON
数据,旨在简化 BSON
数据的构建过程。
d := bsonx.NewD().Add("name", "陈明勇").Add("age", "18").Build()
m := bsonx.M("name", "陈明勇")
e := bsonx.E("name", "陈明勇")
d = bsonx.D("name", "陈明勇")
a := bsonx.A("Mingyong Chen", "陈明勇")
更多用法可前往官网文档 bsonx 包 | go mongox 进行查看。
query 查询构建
query
包为构建 MongoDB
查询条件提供了便捷方法。它包括一系列函数和构建器,旨在简化查询条件的构建。对于复杂查询条件,构建器通过链式调用方式,提供了灵活的构建手段;对于简单需求,则可直接利用函数来快速构建查询条件。
// bson.D{bson.E{Key:"_id", Value:"12345678"}}
/*
{
"_id": "12345678"
}
*/
query.Id("12345678")
// bson.D{bson.E{Key:"name", Value:bson.D{bson.E{Key:"$regex", Value:".*cmy.*"}, bson.E{Key:"$options", Value:"i"}}}}
/*
{
"name": {
"$regex": ".*cmy.*",
"$options": "i"
}
}
*/
query.RegexOptions("name", ".*cmy.*", "i")
// bson.D{bson.E{Key:"age", Value:bson.D{bson.E{Key:"$gte", Value:18}, bson.E{Key:"$lte", Value:25}}}, bson.E{Key:"name", Value:bson.D{bson.E{Key:"$in", Value:[]interface {}{"陈明勇", "chenmingyong"}}}}}
/*
{
"age": {
"$gte": 18,
"$lte": 25
},
"name": {
"$in": ["陈明勇", "Mingyong Chen"]
}
}
*/
query.NewBuilder().Gte("age", 18).Lte("age", 25).In("name", "陈明勇", "Mingyong Chen").Build()
// bson.D{bson.E{Key:"lastLogin", Value:bson.D{bson.E{Key:"$gte", Value:time.Date(2024, time.March, 0, 0, 0, 0, 189625000, time.Local)}}}, bson.E{Key:"$or", Value:[]interface {}{bson.D{bson.E{Key:"status", Value:bson.D{bson.E{Key:"$eq", Value:"active"}}}}, bson.D{bson.E{Key:"loginAttempts", Value:bson.D{bson.E{Key:"$gte", Value:5}}}}}}}
/*
{
"lastLogin": {
"$gte": "2024-03-08T00:00:00.189Z"
},
"$or": [
{
"status": {
"$eq": "active"
}
},
{
"loginAttempts": {
"$gte": 5
}
}
]
}
*/
query.NewBuilder().Gte("lastLogin", time.Now().Add(-30*24*time.Hour)).Or(
query.Eq("status", "active"),
query.Gte("loginAttempts", 5),
).Build()
// bson.D{bson.E{Key:"name", Value:bson.D{bson.E{Key:"$eq", Value:"陈明勇"}}}, bson.E{Key:"hobbies", Value:bson.D{bson.E{Key:"$elemMatch", Value:primie.D{bson.E{Key:"name", Value:bson.D{bson.E{Key:"$eq", Value:"coding"}}}, bson.E{Key:"level", Value:bson.D{bson.E{Key:"$gte", Value:5}}}}}}}}
/*
{
"name": {
"$eq": "陈明勇"
},
"hobbies": {
"$elemMatch": {
"name": {
"$eq": "coding"
},
"level": {
"$gte": 5
}
}
}
}
*/
query.NewBuilder().
Eq("name", "陈明勇").
ElemMatch("hobbies", query.NewBuilder().Eq("name", "coding").Gte("level", 5).Build()).
Build()
更多用法可前往官网文档 query 包 | go mongox 进行查看。
update 更新构建器
update
包为构建 MongoDB
更新文档提供了便捷方法。它包括一系列函数和构建器,旨在简化更新文档的构建。对于复杂的更新文档,构建器通过链式调用方式,提供了灵活的构建手段;对于简单需求,则可直接利用函数来快速构建更新文档。
// bson.D{bson.E{Key:"$set", Value:bson.D{bson.E{Key:"name", Value:"陈明勇"}}}}
/*
{
"$set": {
"name": "陈明勇"
}
}
*/
update.Set("name", "陈明勇")
// bson.D{bson.E{Key:"$inc", Value:bson.D{bson.E{Key:"money", Value:"100000"}}}}
/*
{
"$inc": {
"money": 100000
}
}
*/
update.Inc("money", "100000")
// bson.D{bson.E{Key:"$push", Value:bson.D{bson.E{Key:"tags", Value:"golang"}}}}
/*
{
"$push": {
"tags": "golang"
}
}
*/
update.Push("tags", "golang")
// bson.D{bson.E{Key:"$set", Value:bson.D{bson.E{Key:"name", Value:"陈明勇"}, bson.E{Key:"age", Value:18}}}}
/*{
"$set": {
"name": "陈明勇",
"age": 18
}
}
*/
update.NewBuilder().Set("name", "陈明勇").Set("age", 18).Build()
// bson.D{bson.E{Key:"$set", Value:bson.D{bson.E{Key:"update_at", Value:time.Date(2024, time.April, 7, 3, 13, 23, 958924000, time.Local)}}}, bson.E{Key:"$inc", Value:bson.D{bson.E{Key:"view", Value:1}}}}
/*{
"$set": {
"update_at": "2024-04-07T00:00:00.958Z"
},
"$inc": {
"view": 1
}
}
*/
update.NewBuilder().Set("update_at", time.Now()).Inc("view", 1).Build()
// bson.D{bson.E{Key:"$push", Value:bson.D{bson.E{Key:"comments", Value:"新评论"}}}, bson.E{Key:"$inc", Value:bson.D{bson.E{Key:"commentCount", Value:}}}
/*
{
"$push": {
"comments": "新评论"
},
"$inc": {
"commentCount": 1
}
}
*/
update.NewBuilder().Push("comments", "新评论").Inc("commentCount", 11).Build()
更多用法可前往官网文档 Update 包 | go mongox 进行查看。
aggregation 聚合构建器
aggregation
包提供了方便的方法来构建MongoDB
聚合管道(pipeline)结构。它包括多个函数和构建器,简化了管道构建过程。对于复杂场景,构建器支持链式调用,使得构建过程更加灵活;而对于基础需求,可以直接使用函数快速完成构建。
aggregation
包提供了两种构建器:
aggregation.StageBuilder
:用于轻松构建聚合管道的各个阶段(Pipeline Stages
),如$group
、$match
等。通过aggregation.StageBsonBuilder()
创建一个新的构建器实例,然后调用相应的方法来构建阶段。aggregation.Builder
:用于构建管道阶段内部使用的复杂表达式(Pipeline Expressions
),例如条件逻辑、数学运算等。通过aggregation.BsonBuilder()
创建一个新的构建器实例,然后调用相应的方法来构建表达式。
聚合管道阶段
聚合阶段构建器用于轻松构建聚合管道的各个阶段(Pipeline Stages
),如 $group
、$match
等。
通过 aggregation.NewStageBuilder()
创建一个新的构建器实例,然后调用相应的方法来构建阶段。
// mongo.Pipeline{bson.D{bson.E{Key:"$group", Value:bson.D{bson.E{Key:"_id", Value:"$age"}, bson.E{Key:"count", Value:bson.D{bson.E{Key:"$sum", Value:1}}}, bson.E{Key:"names", Value:bson.D{bson.E{Key:"$push", Value:"$name"}}}}}}}
/*[
{
"$group": {
"_id": "$age",
"count": { "$sum": 1 },
"names": { "$push": "$name" }
}
}
]
*/
aggregation.NewStageBuilder().Group("$age",
aggregation.NewBuilder().Sum("count", 1).Push("names", "$name").Build()...,
).Build()
// mongo.Pipeline{bson.D{bson.E{Key:"$addFields", Value:bson.D{bson.E{Key:"isAdult", Value:bson.D{bson.E{Key:"$gte", Value:[]interface {}{"$age", 18}}}}}}}, bson.D{bson.E{Key:"$replaceWith", Value:bson.D{bson.E{Key:"name", Value:"$name"}, bson.E{Key:"isAdult", Value:"$isAdult"}}}}}
/*
[
{
"$addFields": {
"isAdult": {
"$gte": ["$age", 18]
}
}
},
{
"$replaceWith": {
"name": "$name",
"isAdult": "$isAdult"
}
}
]
*/
aggregation.NewStageBuilder().
AddFields(aggregation.Gte("isAdult", "$age", 18)).
ReplaceWith(bsonx.NewD().Add("name", "$name").Add("isAdult", "$isAdult").Build()).Build()
// mongo.Pipeline{bson.D{bson.E{Key:"$bucket", Value:bson.D{bson.E{Key:"groupBy", Value:"$age"}, bson.E{Key:"boundaries", Value:[]interface {}{0, 19, 31, 46, +Inf}}, bson.E{Key:"default", Value:"Other"}, bson.E{Key:"output", Value:bson.D{bson.E{Key:"count", Value:bson.D{bson.E{Key:"$sum", Value:1}}}, bson.E{Key:"names", Value:bson.D{bson.E{Key:"$push", Value:"$name"}}}}}}}}}
/*
[
{
$bucket: {
groupBy: "$age", // 指定分组的依据字段
boundaries: [0, 19, 31, 46, Infinity], // 定义年龄分组的边界
default: "Other", // 对于不满足任何边界条件的文档,将其分配到一个默认的桶
output: {
"count": { $sum: 1 }, // 计算每个桶中的文档数
"names": { $push: "$name" } // 收集每个桶中所有用户的名字
}
}
}
]
*/
aggregation.NewStageBuilder().Bucket(
"$age",
[]any{
0, 19, 31, 46, math.Inf(1)},
&aggregation.BucketOptions{
DefaultKey: "Other",
Output: aggregation.NewBuilder().Sum("count", 1).Push("names", "$name").Build(),
},
).Build()
聚合表达式
聚合表达式构建器用于轻松构建聚合管道的各个表达式(Expressions
),如 $add
, $subtract
等。
通过 aggregation.BsonBuilder()
创建一个新的构建器实例,然后调用相应的方法来构建表达式。
// bson.D{bson.E{Key:"isAdult", Value:bson.D{bson.E{Key:"$gte", Value:[]interface {}{"$age", 18}}}}}
/*
{
"isAdult": {
"$gte": ["$age", 18]
}
}
*/
aggregation.Gte("isAdult", "$age", 18)
// bson.D{bson.E{Key:"birthYear", Value:bson.D{bson.E{Key:"$subtract", Value:[]interface {}{2024, "$age"}}}}}
/*
{
"birthYear": {
"$subtract": [2024, "$age"]
}
}
*/
aggregation.Subtract("birthYear", 2024, "$age")
// bson.D{bson.E{Key:"age", Value:bson.D{bson.E{Key:"$gt", Value:[]interface {}{18}}}}}
/*
{
"age": {
"$gt": 18
}
}
*/
aggregation.Gt("age", 18)
// bson.D{bson.E{Key:"isAdult", Value:bson.D{bson.E{Key:"$gte", Value:[]interface {}{"$age", 18}}}}, bson.E{Key:"birthYear", Value:bson.D{bson.E{Key:"$subtract", Value:[]interface {}{2024, "$age"}}}}}
/*
{
"isAdult": {
"$gte": ["$age", 18]
},
"birthYear": {
"$subtract": [2024, "$age"]
}
}
*/
aggregation.NewBuilder().
Gte("isAdult", "$age", 18).
Subtract("birthYear", 2024, "$age").Build()
// bson.D{bson.E{Key:"count", Value:bson.D{bson.E{Key:"$sum", Value:1}}}, bson.E{Key:"names", Value:bson.D{bson.E{Key:"$push", Value:"$name"}}}}
/*
{
"count": {
"$sum": 1
},
"names": {
"$push": "$name"
}
}
*/
aggregation.NewBuilder().Sum("count", 1).Push("names", "$name").Build()
// bson.D{bson.E{Key:"count", Value:bson.D{bson.E{Key:"$sum", Value:1}}}, bson.E{Key:"averageAge", Value:bson.D{bson.E{Key:"$avg", Value:"$age"}}}, bson.E{Key:"names", Value:bson.D{bson.E{Key:"$push", Value:"$name"}}}}
/*{
"count": {
"$sum": 1
},
"averageAge": {
"$avg": "$age"
},
"names": {
"$push": "$name"
}
}
*/
aggregation.NewBuilder().
Sum("count", 1).
Avg("averageAge", "$age").
Push("names", "$name").Build()
更多用法可前往官网文档 Aggregation 包 | go mongox 进行查看。
插件化编程
go mongox
支持插件化编程,它提供了一种灵活的方式在数据库操作的前后插入自定义的逻辑,从而增强应用的可扩展性和可维护性。go mongox
提供了 RegisterPlugin
和 UnregisterPlugin
方法来注册和删除插件。
type User struct {
mongox.Model `bson:"inline"`
Name string `bson:"name"`
Age int `bson:"age"`
}
// 注册插件
mongox.RegisterPlugin("after find", func(ctx context.Context, opCtx *operation.OpContext, opts ...any) error {
if user, ok := opCtx.Doc.(*User); ok {
fmt.Println(user)
}
if users, ok := opCtx.Doc.([]*User); ok {
fmt.Println(users)
}
return nil
}, operation.OpTypeAfterFind)
// 移除插件
mongox.RemovePlugin("after find", operation.OpTypeAfterFind)
激活内置的插件(钩子)
go mongox
库内置了三个实用的 hook
钩子:
field
钩子:自动化更新默认的field
字段model
钩子:针对模型(结构体)设置钩子函数,这些钩子函数会在MongoDB
的集合操作前后被调用。validator
钩子:利用结构体的标签(tag
)去对字段值进行校验。
go mongox
库默认不激活这些钩子,如果你想激活它们,可以参考以下代码:
mongox.InitPlugin(&mongox.PluginConfig{
EnableDefaultFieldHook: true,
EnableModelHook: true,
EnableValidationHook: true,
// 覆盖默认的校验器,当 EnableValidationHook 为 true 时生效
Validate: nil,
})
这三个内置钩子的内容会在下面进行介绍。
更多用法可前往官网文档 插件化编程 | go mongox 进行查看。
结构体 tag 校验
go mongox
库支持利用结构体的标签(tag
)去对字段值进行校验,这一校验功能基于 playground/validator 库提供的所有结构体校验规则。
type User struct {
mongox.Model `bson:"inline"`
Name string `bson:"name"`
Age uint8 `validate:"gte=0,lte=130"` // 确保年龄在 0 到 130 岁之间
Email string `json:"e-mail" validate:"required,email"` // 表示这个字段在数据验证时是必需的,并且必须符合电子邮箱的格式。
FavouriteColor string `validate:"hexcolor|rgb|rgba"` // 确保提供的颜色值要么是十六进制颜色码,要么是RGB或RGBA格式。
}
结构体 tag 校验功能默认是关闭的,如需开启,请使用 mongox.InitPlugin
函数。
更多用法可前往官网文档 结构体校验 | go mongox 进行查看。
内置 Model
go mongox
内置了一个 Model
结构体,它包含了 ID
、CreatedAt
和 UpdatedAt
三个字段。
type Model struct {
ID primitive.ObjectID `bson:"_id,omitempty"`
CreatedAt time.Time `bson:"created_at"`
UpdatedAt time.Time `bson:"updated_at"`
}
func (m *Model) DefaultId() {
if m.ID.IsZero() {
m.ID = primitive.NewObjectID()
}
}
func (m *Model) DefaultCreatedAt() {
if m.CreatedAt.IsZero() {
m.CreatedAt = time.Now().Local()
}
}
func (m *Model) DefaultUpdatedAt() {
m.UpdatedAt = time.Now().Local()
}
这个结构体实现了 DefaultModelHook
接口,如果初始化插件时将 EnableDefaultFieldHook
设置为 true(详情请参考 启用内置插件-钩子 ),go mongox
库将自动化地处理文档的创建、更新操作中的 ID
和时间的赋值。
更多用法可前往官网文档 内置 Model | go mongox 进行查看。
Hook 钩子
模型钩子(Model Hooks)
你可以针对模型(结构体)设置钩子函数,这些钩子函数会在 MongoDB
的集合操作前后被调用。例如,你可以在插入文档前后对文档进行处理,或者在查询文档后对文档进行处理。
type User struct {
mongox.Model `bson:"inline"`
Name string `bson:"name"`
Age int `bson:"age"`
}
func (u *User) BeforeInsert(ctx context.Context) error {
fmt.Println("BeforeInsert called")
return nil
}
func (u *User) AfterInsert(ctx context.Context) error {
fmt.Println("AfterInsert called")
return nil
}
func (u *User) AfterFind(ctx context.Context) error {
fmt.Println("AfterFind called")
return nil
}
func (u *User) BeforeUpsert(ctx context.Context) error {
fmt.Println("BeforeUpsert called")
return nil
}
func (u *User) AfterUpsert(ctx context.Context) error {
fmt.Println("AfterUpsert called")
return nil
}
更多用法可前往官网文档 模型钩子(Model Hooks) | go mongox 进行查看。
一次性钩子
go mongox
支持一次性钩子,你可以在查询、插入、删除、更新和保存文档的前后执行一些操作。
// 插入操作
_, err = userColl.Creator().
RegisterBeforeHooks(func(ctx context.Context, opContext *creator.OpContext[User], opts ...any) error {
fmt.Println("BeforeHook called")
fmt.Println(opContext.Doc)
fmt.Println(opContext.Col != nil)
return nil
}).
RegisterAfterHooks(func(ctx context.Context, opContext *creator.OpContext[User], opts ...any) error {
fmt.Println("AfterHook called")
fmt.Println(opContext.Doc)
fmt.Println(opContext.Col != nil)
return nil
}).
InsertOne(context.Background(), &User{
Name: "Mingyong Chen", Age: 18})
// 查询操作
_, err = userColl.Finder().
RegisterBeforeHooks(func(ctx context.Context, opContext *finder.OpContext, opts ...any) error {
fmt.Println("BeforeHook called")
fmt.Println(opContext.Filter)
return nil
}).
RegisterAfterHooks(func(ctx context.Context, opContext *finder.AfterOpContext[User], opts ...any) error {
fmt.Println("AfterHook called")
fmt.Println(opContext.Filter)
fmt.Println(opContext.Doc)
return nil
}).
Filter(query.Eq("name", "陈明勇")).FindOne(context.Background())
// 更新操作
_, err = userColl.Updater().
RegisterBeforeHooks(func(ctx context.Context, opContext *updater.BeforeOpContext, opts ...any) error {
fmt.Println("BeforeHook called")
fmt.Println(opContext.Filter)
fmt.Println(opContext.Updates)
fmt.Println(opContext.Col != nil)
return nil
}).
RegisterAfterHooks(func(ctx context.Context, opContext *updater.AfterOpContext, opts ...any) error {
fmt.Println("AfterHook called")
fmt.Println(opContext.Filter)
fmt.Println(opContext.Updates)
fmt.Println(opContext.Col != nil)
return nil
}).
Filter(query.Eq("name", "陈明勇")).
Updates(update.Set("age", 19)).
UpdateOne(context.Background())
// 删除操作
_, err = userColl.Deleter().
RegisterBeforeHooks(func(ctx context.Context, opContext *deleter.BeforeOpContext, opts ...any) error {
fmt.Println("BeforeHook called")
fmt.Println(opContext.Filter)
fmt.Println(opContext.Col != nil)
return nil
}).
RegisterAfterHooks(func(ctx context.Context, opContext *deleter.AfterOpContext, opts ...any) error {
fmt.Println("AfterHook called")
fmt.Println(opContext.Filter)
fmt.Println(opContext.Col != nil)
return nil
}).
Filter(query.Eq("name", "Mingyong Chen")).
DeleteOne(context.Background())
更多用法可前往官网文档 一次性钩子 | go mongox 进行查看。
小结
本文详细介绍了 go mongox
库的关键模块,包括创建指定约束类型的泛型 Collection
、灵活的 BSON
构建器、基础的 CRUD
操作、聚合操作、以及插件和钩子机制,并提供了相应的使用示例。
仓库地址:https://github.com/chenmingyong0423/go-mongox
欢迎体验
go mongox
库,也期待您的贡献。如果您觉得这个库对您有帮助,请给它一个 Star 支持!