go-mongox:简单高效,让文档操作和 bson 数据构造更流畅
前言
在 Go 语言中使用 MongoDB 官方框架进行集合操作时,深深感到构建 bson 数据是一件非常繁琐的工作。字段、逗号,括号等符号的排列,让我感觉仿佛是在进行一场拼图游戏。因此我在想,有没有一个能让我丝滑,高效操作 MongoDB 的第三方框架呢,遗憾的是,并没有找到符合我预期的框架,索性我就自己动手开发了一个,这就是 go-mongox 框架的由来。
如果你也有类似我的这种感受,相信 go-mongox 框架能给你带来不一样的体验。
go-mongox
go-mongox 基于 泛型 对 MongoDB 官方框架进行了二次封装,它通过使用链式调用的方式,让我们能够丝滑地操作文档。同时,其还提供了多种类型的 bson 构造器,帮助我们高效的构建 bson 数据。
仓库地址:github.com/chenmingyong0423/go-mon...
官方文档链接:go-mongox.dev
该框架处于初期阶段,希望通过集思广益的方式,邀请各位开发者共同参与,提出宝贵的建议和意见,共同打造一个更强大、更灵活的框架。期待着您的积极参与和宝贵反馈,共同推动
go-mongox不断进步。
功能
- 文档的
CRUD操作 - 聚合操作
- 内置基本的
Model结构体,自动化更新默认的field字段 - 支持
bson数据的构建 - Hooks
- 支持插件化编程
安装
go get github.com/chenmingyong0423/go-mongox@latest
collection 集合操作
基于泛型的 collection 形态初始化
package main
import (
"context"
"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 Post struct {
Id primitive.ObjectID `bson:"_id,omitempty"`
Title string `bson:"title"`
Author string `bson:"author"`
Content string `bson:"content"`
}
func main() {
// 你需要预先创建一个 *mongo.Collection 对象
mongoCollection := newCollection()
// 使用 Post 结构体作为泛型参数创建一个 collection
postCollection := mongox.NewCollection[Post](mongoCollection)
}
// 示例代码,不是最佳的创建方式
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 装饰器。
Creator 创造器
Creator 是一个创造器,用于执行插入相关的操作。
插入单个文档
// https://github.com/chenmingyong0423/blog/blob/master/tutorial-code/go-mongox/collection/creator/insert_one.go
package main
import (
"chenmingyong0423/blog/tutorial-code/go-mongox/collection"
"context"
"fmt"
"go.mongodb.org/mongo-driver/mongo/options"
"github.com/chenmingyong0423/go-mongox"
)
func main() {
// 你需要预先创建一个 *mongo.Collection 对象
mongoCollection := collection.NewCollection()
// 使用 Post 结构体作为泛型参数创建一个 collection
postCollection := mongox.NewCollection[collection.Post](mongoCollection)
ctx := context.Background()
// 插入一个文档
doc := collection.Post{Title: "go 语言 go-mongox 库的使用教程", Author: "陈明勇", Content: "go-mongox 旨在提供更方便和高效的MongoDB数据操作体验。"}
oneResult, err := postCollection.Creator().InsertOne(ctx, doc)
if err != nil {
panic(err)
}
fmt.Println(oneResult.InsertedID != nil) // true
// 携带 option 参数
oneResult, err = postCollection.Creator().InsertOne(ctx, doc, options.InsertOne().SetComment("test"))
if err != nil {
panic(err)
}
fmt.Println(oneResult.InsertedID != nil) // true
}
基于 postCollection 实例,我们可以通过 Creator() 方法创建一个创造器,然后进行插入操作。
InsertOne 方法与官方的 API 同名,作用是插入一条数据。如果我们需要设置 options 参数,可以将其作为该方法的第三个参数传递。
插入多个文档
// https://github.com/chenmingyong0423/blog/blob/master/tutorial-code/go-mongox/collection/creator/insert_many.go
package main
import (
"chenmingyong0423/blog/tutorial-code/go-mongox/collection"
"context"
"fmt"
"github.com/chenmingyong0423/go-mongox"
"go.mongodb.org/mongo-driver/mongo/options"
)
func main() {
// 你需要预先创建一个 *mongo.Collection 对象
mongoCollection := collection.NewCollection()
// 使用 Post 结构体作为泛型参数创建一个 collection
postCollection := mongox.NewCollection[collection.Post](mongoCollection)
ctx := context.Background()
docs := []collection.Post{
{Title: "go-mongox", Author: "陈明勇", Content: "..."},
{Title: "builder", Author: "陈明勇", Content: "..."},
}
manyResult, err := postCollection.Creator().InsertMany(ctx, docs)
if err != nil {
panic(err)
}
fmt.Println(len(manyResult.InsertedIDs) == 2) // true
// 携带 option 参数
manyResult, err = postCollection.Creator().InsertMany(ctx, docs, options.InsertMany().SetComment("test"))
if err != nil {
panic(err)
}
fmt.Println(len(manyResult.InsertedIDs) == 2) // true
}
InsertMany 方法与官方的 API 同名,作用是插入多条数据。如果我们需要设置 options 参数,可以将其作为该方法的第三个参数传递。
Finder 查询器
Finder 是一个查询器,用于执行查询相关的操作。
查询单个文档
// https://github.com/chenmingyong0423/blog/blob/master/tutorial-code/go-mongox/collection/finder/find_one.go
package main
import (
"chenmingyong0423/blog/tutorial-code/go-mongox/collection"
"context"
"fmt"
"go.mongodb.org/mongo-driver/mongo/options"
"github.com/chenmingyong0423/go-mongox"
"github.com/chenmingyong0423/go-mongox/bsonx"
"github.com/chenmingyong0423/go-mongox/builder/query"
)
func main() {
// 你需要预先创建一个 *mongo.Collection 对象
mongoCollection := collection.NewCollection()
// 使用 Post 结构体作为泛型参数创建一个 collection
postCollection := mongox.NewCollection[collection.Post](mongoCollection)
oneResult, err := postCollection.Creator().InsertOne(context.Background(), collection.Post{Title: "go-mongox", Author: "陈明勇", Content: "go-mongox 旨在提供更方便和高效的MongoDB数据操作体验。"})
if err != nil {
panic(err)
}
// 查询单个文档
post, err := postCollection.Finder().Filter(query.Id(oneResult.InsertedID)).FindOne(context.Background())
if err != nil {
panic(err)
}
fmt.Println(post)
// 设置 *options.FindOneOptions 参数
post2, err := postCollection.Finder().
Filter(query.Id(oneResult.InsertedID)).
FindOne(context.Background(), options.FindOne().SetProjection(bsonx.M("content", 0)))
if err != nil {
panic(err)
}
fmt.Println(post2)
// - map 作为 filter 条件
post3, err := postCollection.Finder().Filter(map[string]any{"_id": oneResult.InsertedID}).FindOne(context.Background())
if err != nil {
panic(err)
}
fmt.Println(post3)
// - 复杂条件查询
// -- 使用 query 包构造复杂的 bson: bson.D{bson.E{Key: "title", Value: bson.M{"$eq": "go"}}, bson.E{Key: "author", Value: bson.M{"$eq": "陈明勇"}}}
post4, err := postCollection.Finder().
Filter(query.BsonBuilder().Eq("title", "go-mongox").Eq("author", "陈明勇").Build()).
FindOne(context.Background())
if err != nil {
panic(err)
}
fmt.Println(post4)
}
基于 postCollection 实例,我们可以通过 Finder() 方法创建一个查询器,然后进行查询操作。
FindOne 方法与官方的 API 同名,作用是查询单个文档。我们可以通过 Filter 方法设置 查询条件,如果我们需要设置 options 参数,可以将其作为 FindOne 方法的第二个参数传递。
对于简单的查询条件,我们可以使用 query 包提供的函数进行构造,例如 query.Id(id);对于复杂的查询条件,我们可以使用 query 包提供的 BsonBuilder构造器进行构造。query 包的用法会在下面的内容进行详细地介绍。
查询多个文档
// https://github.com/chenmingyong0423/blog/blob/master/tutorial-code/go-mongox/collection/finder/find.go
package main
import (
"chenmingyong0423/blog/tutorial-code/go-mongox/collection"
"context"
"fmt"
"github.com/chenmingyong0423/go-mongox"
"github.com/chenmingyong0423/go-mongox/bsonx"
"github.com/chenmingyong0423/go-mongox/builder/query"
"go.mongodb.org/mongo-driver/mongo/options"
)
func main() {
ctx := context.Background()
// 你需要预先创建一个 *mongo.Collection 对象
mongoCollection := collection.NewCollection()
// 使用 Post 结构体作为泛型参数创建一个 collection
postCollection := mongox.NewCollection[collection.Post](mongoCollection)
_, err := postCollection.Creator().InsertMany(ctx, []collection.Post{
{Title: "go-mongox", Author: "陈明勇", Content: "go-mongox 旨在提供更方便和高效的MongoDB数据操作体验。"},
{Title: "mongo", Author: "陈明勇", Content: "..."},
})
if err != nil {
panic(err)
}
// 查询多个文档
// bson.D{bson.E{Key: "title", Value: bson.M{"$in": []string{"go-mongox", "mongo"}}}}
posts, err := postCollection.Finder().
Filter(query.In("title", []string{"go-mongox", "mongo"}...)).
Find(ctx)
if err != nil {
panic(err)
}
for _, post := range posts {
fmt.Println(post)
}
// 设置 *options.FindOptions 参数
// bson.D{bson.E{Key: "title", Value: bson.M{"$in": []string{"go-mongox", "mongo"}}}}
posts2, err := postCollection.Finder().
Filter(query.In("title", []string{"go-mongox", "mongo"}...)).
Find(ctx, options.Find().SetProjection(bsonx.M("content", 0)))
if err != nil {
panic(err)
}
for _, post := range posts2 {
fmt.Println(post)
}
}
Find 方法与官方的 API 同名,作用是查询多个文档。如果我们需要设置 options 参数,可以将其作为 Find 方法的第二个参数传递。
在上面的例子中,为了构造 $in 查询语句,我们使用了 query 包提供的泛型函数 In。
Updater 更新器
Updater 是一个更新器,用于执行更新相关的操作。
更新单个文档
// https://github.com/chenmingyong0423/blog/blob/master/tutorial-code/go-mongox/collection/updater/update_one.go
package main
import (
"chenmingyong0423/blog/tutorial-code/go-mongox/collection"
"context"
"fmt"
"go.mongodb.org/mongo-driver/mongo/options"
"github.com/chenmingyong0423/go-mongox/builder/query"
"github.com/chenmingyong0423/go-mongox"
"github.com/chenmingyong0423/go-mongox/bsonx"
"github.com/chenmingyong0423/go-mongox/builder/update"
"github.com/chenmingyong0423/go-mongox/types"
)
func main() {
ctx := context.Background()
// 你需要预先创建一个 *mongo.Collection 对象
mongoCollection := collection.NewCollection()
// 使用 Post 结构体作为泛型参数创建一个 collection
postCollection := mongox.NewCollection[collection.Post](mongoCollection)
oneResult, err := postCollection.Creator().InsertOne(ctx, collection.Post{Title: "go-mongox", Author: "陈明勇", Content: "go-mongox 旨在提供更方便和高效的MongoDB数据操作体验。"})
if err != nil {
panic(err)
}
// 更新单个文档
// 通过 update 包构建 bson 更新语句
updateResult, err := postCollection.Updater().
Filter(query.Id(oneResult.InsertedID)).
Updates(update.Set("title", "golang")).
UpdateOne(ctx)
if err != nil {
panic(err)
}
fmt.Println(updateResult.ModifiedCount == 1) // true
// - 使用 map 构造更新数据,并设置 *options.UpdateOptions,执行 upsert 操作
updateResult2, err := postCollection.Updater().
Filter(bsonx.Id("custom-id")).
UpdatesWithOperator(types.Set, bsonx.M("title", "mongo")).
UpdateOne(ctx, options.Update().SetUpsert(true))
if err != nil {
panic(err)
}
fmt.Println(updateResult2.UpsertedID.(string) == "custom-id") // true
}
基于 postCollection 实例,我们可以通过 Updater() 方法创建一个更新器,然后进行更新操作。
UpdateOne 方法与官方的 API 同名,作用是更新单个文档。我们可以通过 Filter 方法设置 文档匹配的条件,如果我们需要设置 options 参数,可以将其作为 UpdateOne 方法的第二个参数传递。
对于更新操作参数,我们可以使用以下两个方法进行设置:
Updates方法:该方法接收bson或map等合法的更新操作语句。上面的例子使用了update包里的Set对更新操作语句进行构造。UpdatesWithOperator方法:该方法的第一个参数为更新操作符,第二个参数为预期更新的数据。上面的例子使用了bsonx包构造bson数据。
更新多个文档
// https://github.com/chenmingyong0423/blog/blob/master/tutorial-code/go-mongox/collection/updater/update_many.go
package main
import (
"chenmingyong0423/blog/tutorial-code/go-mongox/collection"
"context"
"fmt"
"github.com/chenmingyong0423/go-mongox"
"github.com/chenmingyong0423/go-mongox/builder/query"
"github.com/chenmingyong0423/go-mongox/builder/update"
)
func main() {
ctx := context.Background()
// 你需要预先创建一个 *mongo.Collection 对象
mongoCollection := collection.NewCollection()
// 使用 Post 结构体作为泛型参数创建一个 collection
postCollection := mongox.NewCollection[collection.Post](mongoCollection)
_, err := postCollection.Creator().InsertMany(ctx, []collection.Post{
{Title: "go-mongox", Author: "陈明勇", Content: "go-mongox 旨在提供更方便和高效的MongoDB数据操作体验。"},
{Title: "builder", Author: "陈明勇", Content: "..."},
})
if err != nil {
panic(err)
}
// 更新多个文档
updateResult, err := postCollection.Updater().
Filter(query.In("title", []string{"go-mongox", "builder"}...)).
Updates(update.Set("title", "golang")).
UpdateMany(ctx)
if err != nil {
panic(err)
}
fmt.Println(updateResult.ModifiedCount == 2) // true
}
UpdateMany 方法与官方的 API 同名,作用是更新多个文档。
Deleter 删除器
Deleter 是一个删除器,用于执行删除相关的操作。
删除单个文档
// https://github.com/chenmingyong0423/blog/blob/master/tutorial-code/go-mongox/collection/deleter/delete_one.go
package main
import (
"chenmingyong0423/blog/tutorial-code/go-mongox/collection"
"context"
"fmt"
"github.com/chenmingyong0423/go-mongox/builder/query"
"go.mongodb.org/mongo-driver/mongo/options"
"github.com/chenmingyong0423/go-mongox"
)
func main() {
ctx := context.Background()
// 你需要预先创建一个 *mongo.Collection 对象
mongoCollection := collection.NewCollection()
// 使用 Post 结构体作为泛型参数创建一个 collection
postCollection := mongox.NewCollection[collection.Post](mongoCollection)
_, err := postCollection.Creator().InsertMany(ctx, []collection.Post{
{Title: "go-mongox", Author: "陈明勇", Content: "go-mongox 旨在提供更方便和高效的MongoDB数据操作体验。"},
{Title: "builder", Author: "陈明勇", Content: "..."},
})
if err != nil {
panic(err)
}
// 删除单个文档
deleteResult, err := postCollection.Deleter().Filter(query.Eq("title", "go-mongox")).DeleteOne(ctx)
if err != nil {
panic(err)
}
fmt.Println(deleteResult.DeletedCount == 1) // true
// 携带 option 参数
deleteResult2, err := postCollection.Deleter().Filter(query.Eq("title", "builder")).DeleteOne(ctx, options.Delete().SetComment("test"))
if err != nil {
panic(err)
}
fmt.Println(deleteResult2.DeletedCount == 1) // true
}
基于 postCollection 实例,我们可以通过 Deleter() 方法创建一个删除器,然后进行删除操作。
DeleteOne 方法与官方的 API 同名,作用是删除单个文档。我们可以通过 Filter 方法设置 文档匹配的条件。如果我们需要设置 options 参数,可以将其作为 DeleteOne 方法的第二个参数传递。
删除多个文档
// https://github.com/chenmingyong0423/blog/blob/master/tutorial-code/go-mongox/collection/deleter/delete_many.go
package main
import (
"chenmingyong0423/blog/tutorial-code/go-mongox/collection"
"context"
"fmt"
"github.com/chenmingyong0423/go-mongox"
"github.com/chenmingyong0423/go-mongox/builder/query"
)
func main() {
ctx := context.Background()
// 你需要预先创建一个 *mongo.Collection 对象
mongoCollection := collection.NewCollection()
// 使用 Post 结构体作为泛型参数创建一个 collection
postCollection := mongox.NewCollection[collection.Post](mongoCollection)
_, err := postCollection.Creator().InsertMany(ctx, []collection.Post{
{Title: "go-mongox", Author: "陈明勇", Content: "go-mongox 旨在提供更方便和高效的MongoDB数据操作体验。"},
{Title: "builder", Author: "陈明勇", Content: "..."},
})
if err != nil {
panic(err)
}
// 删除多个文档
// - 通过 query 包构造复杂的 bson 语句
deleteResult, err := postCollection.Deleter().
Filter(query.In("title", "go-mongox", "builder")).
DeleteMany(ctx)
if err != nil {
panic(err)
}
fmt.Println(deleteResult.DeletedCount == 2) // true
}
DeleteMany 方法与官方的 API 同名,作用是删除多个文档。
Aggregator 聚合器
Aggregator 是一个聚合器,用于执行聚合相关的操作。
// https://github.com/chenmingyong0423/blog/blob/master/tutorial-code/go-mongox/collection/aggregator/aggregator.go
package main
import (
"chenmingyong0423/blog/tutorial-code/go-mongox/collection"
"context"
"fmt"
"github.com/chenmingyong0423/go-mongox"
"github.com/chenmingyong0423/go-mongox/bsonx"
"github.com/chenmingyong0423/go-mongox/builder/aggregation"
"go.mongodb.org/mongo-driver/mongo"
)
func main() {
ctx := context.Background()
// 你需要预先创建一个 *mongo.Collection 对象
mongoCollection := collection.NewCollection()
// 使用 Post 结构体作为泛型参数创建一个 collection
postCollection := mongox.NewCollection[collection.Post](mongoCollection)
_, err := postCollection.Creator().InsertMany(ctx, []collection.Post{
{Title: "go-mongox", Author: "陈明勇", Content: "go-mongox 旨在提供更方便和高效的MongoDB数据操作体验。"},
{Title: "builder", Author: "陈明勇", Content: "..."},
})
if err != nil {
panic(err)
}
// 聚合操作
// - 使用 aggregation 包构造 pipeline
posts, err := postCollection.
// 去除 content 字段
Aggregator().Pipeline(aggregation.StageBsonBuilder().Project(bsonx.M("content", 0)).Build()).
Aggregate(ctx)
if err != nil {
panic(err)
}
for _, post := range posts {
fmt.Println(post)
}
// 如果我们通过聚合操作更改字段的名称,那么我们可以使用 AggregationWithCallback 方法,然后通过 callback 函数将结果映射到我们预期的结构体中
type DiffPost struct {
Id string `bson:"_id"`
Title string `bson:"title"`
Name string `bson:"name"` // author → name
Content string `bson:"content"`
Outstanding bool `bson:"outstanding"`
}
result := make([]*DiffPost, 0)
// 将 author 字段更名为 name,排除 content 字段,添加 outstanding 字段,返回结果为 []*DiffPost
err = postCollection.Aggregator().
Pipeline(
aggregation.StageBsonBuilder().Project(
bsonx.NewD().Add("name", "$author").Add("author", 1).Add("_id", 1).Add("title", 1).Add("outstanding", aggregation.Eq("$author", "陈明勇")).Build(),
).Build(),
).
AggregateWithCallback(ctx, func(ctx context.Context, cursor *mongo.Cursor) error {
return cursor.All(ctx, &result)
})
for _, post := range result {
fmt.Println(post)
}
}
基于 postCollection 实例,我们可以通过 Aggregator() 方法创建一个聚合器,然后进行聚合操作。
我们可以通过 Pipeline 方法设置 pipeline 参数。
对于执行聚合操作,有以下两个方法:
Aggregate方法:与官方的API同名。AggregateWithCallback方法:因为我们在创建collection装饰器时,使用泛型绑定了一个结构体,如果我们执行聚合操作之后,返回的数据与所绑定的结构体映射不上,这时可以使用该方法将结果映射到指定的结构体里。
bson 数据构造
go-mongox 框架提供了以下几种类型的构造器:
universal: 简单而又通用的bson数据构造函数。query: 查询构造,用于构造查询操作所需的bson数据。update: 更新构造,用于构造更新操作所需的bson数据。aggregation: 聚合操作构造,包含两种,一种是用于构造聚合stage阶段所需的bson数据,另一种是用于构造除了stage阶段以外的bson数据。
universal 通用构造
我们可以使用 bsonx 包里的一些函数进行 bson 数据的构造,例如 bsonx.M、bsonx.Id 和 bsonx.D 等等。
// https://github.com/chenmingyong0423/blog/blob/master/tutorial-code/go-mongox/builder/universal.go
package main
import (
"fmt"
"github.com/chenmingyong0423/go-mongox/bsonx"
)
func main() {
// bson.M{"姓名": "陈明勇"}
m := bsonx.M("姓名", "陈明勇")
fmt.Printf("%#v\n\n", m)
// bson.M{"_id": "陈明勇"}
id := bsonx.Id("陈明勇")
fmt.Printf("%#v\n\n", id)
// bson.E{Key:"姓名", Value:"陈明勇"}
e := bsonx.E("姓名", "陈明勇")
fmt.Printf("%#v\n\n", e)
// bson.D{bson.E{Key:"姓名", Value:"陈明勇"}, bson.E{Key:"手机号", Value:"1888***1234"}}
d := bsonx.D(bsonx.E("姓名", "陈明勇"), bsonx.E("手机号", "1888***1234"))
fmt.Printf("%#v\n\n", d)
// 我们还可以使用 bsonx.DBuilder 来构建 bson.D
d2 := bsonx.NewD().Add("姓名", "陈明勇").Add("手机号", "1888***1234").Build()
fmt.Printf("%#v\n\n", d2)
// bson.A{"陈明勇", "1888***1234"}
a := bsonx.A("陈明勇", "1888***1234")
fmt.Printf("%#v", a)
}
bsonx 包暂时提供了这些构造函数,后面会持续添加更多有用的函数。
query 查询构造
query 包可以帮我们构造出查询相关的 bson 数据,例如 $in、$gt、$and 等等。
构造类型包含两种:
直接构造
query包提供许多构造函数,能够帮我们快速地构造简单的bson数据,例如query.Id、query.In和query.Eq等。构造器构造
简单的bson数据,我们只需要使用query包提供的函数即可。但当我们需要构造复杂或多级条件的bson数据时,我们可以使用BsonBuilder构造器。
// https://github.com/chenmingyong0423/blog/blob/master/tutorial-code/go-mongox/builder/query.go
package main
import (
"fmt"
"github.com/chenmingyong0423/go-mongox/bsonx"
"github.com/chenmingyong0423/go-mongox/builder/query"
)
func main() {
// 通过函数直接构造
// bson.D{bson.E{Key:"姓名", Value:bson.D{bson.E{Key:"$eq", Value:"陈明勇"}}}}
d := query.Eq("姓名", "陈明勇")
fmt.Printf("%#v\n\n", d)
// bson.D{bson.E{Key:"age", Value:bson.D{{Key:"$in", Value:[]int{18, 19, 20}}}}}
d = query.In("age", 18, 19, 20)
fmt.Printf("%#v\n\n", d)
// elemMatch
// bson.D{bson.E{Key: "result", Value: bson.D{bson.E{Key: "$elemMatch", Value: bson.D{bson.E{Key: "$gte", Value: 80}, bson.E{Key: "$lt", Value: 85}}}}}}
d = query.ElemMatch("result", bsonx.D(bsonx.E("$gte", 80), bsonx.E("$lt", 85)))
fmt.Printf("%#v\n\n", d)
// 通过构造器构造
// bson.D{bson.E{Key:"age", Value:bson.D{{Key:"$gt", Value:18}, bson.E{Key:"$lt", Value:25}}}}
d = query.BsonBuilder().Gt("age", 18).Lt("age", 25).Build()
fmt.Printf("%#v\n\n", d)
// bson.d{bson.E{Key: "$and", Value: []any{bson.D{{Key: "x", Value: bson.D{{Key: "$ne", Value: 0}}}}, bson.D{{Key: "y", Value: bson.D{{Key: "$gt", Value: 0}}}}}}
d = query.BsonBuilder().And(
query.BsonBuilder().Ne("x", 0).Build(),
query.BsonBuilder().Gt("y", 0).Build(),
).Build()
fmt.Printf("%#v\n\n", d)
// bson.D{bson.E{Key:"qty", Value:bson.D{{Key:"$exists", Value:true}, bson.E{Key:"$nin", Value:[]int{5, 15}}}}}
d = query.BsonBuilder().Exists("qty", true).NinInt("qty", 5, 15).Build()
fmt.Printf("%#v", d)
}
query 包提供的方法不止这些,以上只是列举出一些典型的例子,还有更多的用法等着你去探索。
update 更新构造器
update 包可以帮我们构造出更新操作相关的 bson 数据,例如 $set、$$inc、$push 等等。
构造类型包含两种:
直接构造
update包提供许多构造函数,能够帮我们快速地构造简单的bson数据,例如update.SetSimple、update.Inc和update.Push等。构造器构造
简单的bson数据,我们只需要使用update包提供的函数即可。但当我们需要构造复杂或多级条件的bson数据时,我们可以使用BsonBuilder构造器。
// https://github.com/chenmingyong0423/blog/blob/master/tutorial-code/go-mongox/builder/update.go
package main
import (
"fmt"
"github.com/chenmingyong0423/go-mongox/builder/update"
)
func main() {
// 通过函数直接构造
// bson.D{bson.E{Key:"$set", Value:bson.M{"name":"陈明勇"}}}
u := update.Set("name", "陈明勇")
fmt.Printf("%#v\n\n", u)
// bson.D{bson.E{Key:"$inc", Value:bson.D{bson.E{Key:"ratings", Value:-1}}}}
u = update.BsonBuilder().Inc("ratings", -1).Build()
fmt.Printf("%#v\n\n", u)
// bson.D{bson.E{Key:"$push", Value:bson.M{"scores":95}}}
u = update.BsonBuilder().Push("scores", 95).Build()
fmt.Printf("%#v\n\n", u)
// 通过构造器构造
// bson.D{bson.E{Key:"$set", Value:bson.D{bson.E{Key:"name", Value:"陈明勇"}, bson.E{Key:"sex", Value:"男"}}}}
u = update.BsonBuilder().Set("name", "陈明勇").Set("sex", "男").Build()
fmt.Printf("%#v\n\n", u)
// bson.D{bson.E{Key:"$set", Value:bson.D{bson.E{Key:"name", Value:"陈明勇"}}}, bson.E{Key:"$inc", Value:bson.D{bson.E{Key:"rating Value:-1}}}, bson.E{Key:"$push", Value:bson.D{bson.E{Key:"scores", Value:95}}}}
u = update.BsonBuilder().Set("name", "陈明勇").Inc("ratings", -1).Push("scores", 95).Build()
fmt.Printf("%#v\n\n", u)
}
update 包提供的方法不止这些,以上只是列举出一些典型的例子,还有更多的用法等着你去探索。
aggregation 聚合构造器
aggregation 包提供了两个 builder:
StageBsonBuilder:用于构造stage阶段所需的bson数据BsonBuilder:用于构造除了stage阶段以外的bson数据。
// https://github.com/chenmingyong0423/blog/blob/master/tutorial-code/go-mongox/builder/aggregation.go
package main
import (
"fmt"
"github.com/chenmingyong0423/go-mongox/bsonx"
"github.com/chenmingyong0423/go-mongox/builder/aggregation"
"github.com/chenmingyong0423/go-mongox/types"
)
func main() {
// bson.D{bson.E{Key:"total", Value:bson.D{bson.E{Key:"$gt", Value:[]interface {}{"$price", "$fee"}}}}}
gt := aggregation.Gt("total", []any{"$price", "$fee"}...)
fmt.Printf("%#v\n\n", gt)
// mongo.Pipeline{bson.D{bson.E{Key:"$project", Value:bson.D{bson.E{Key:"name", Value:1}, bson.E{Key:"qtyGt250", Value:bson.D{bson.E{Key:"total", Value:bson.D{bson.E{Key:"$gt", Value:[]interface {}{"$price", "$fee"}}}}}}}}}}
pipeline := aggregation.StageBsonBuilder().
Project(bsonx.NewD().Add("name", 1).Add("qtyGt250", gt).Build()).
Build()
fmt.Printf("%#v\n\n", pipeline)
// bson.D{bson.E{Key:"result", Value:bson.D{bson.E{Key:"$or", Value:[]interface {}{bson.D{bson.E{Key:"$gt", Value:[]interface {}{"score", 70}}, bson.E{Key:"score", Value:bson.D{bson.E{Key:"$lt", Value:[]interface {}{90}}}}}, bson.D{bson.E{Key:"views", Value:bson.D{bson.E{Key:"$gte", Value:[]interface {}{90}}}}}}}}}}
or := aggregation.BsonBuilder().Or("result", aggregation.BsonBuilder().GtWithoutKey("score", 70).Lt("score", 90).Build(), aggregation.BsonBuilder().Gte("views", 90).Build()).Build()
fmt.Printf("%#v\n\n", or)
// mongo.Pipeline{bson.D{bson.E{Key:"$match", Value:bson.D{bson.E{Key:"result", Value:bson.D{bson.E{Key:"$or", Value:[]interface {}{bson.D{bson.E{Key:"$gt", Value:[]interface {}{"score", 70}}, bson.E{Key:"score", Value:bson.D{bson.E{Key:"$lt", Value:[]interface {}{90}}}}}, bson.D{bson.E{Key:"views", Value:bson.D{bson.E{Key:"$gte", Value:[]interface {}{90}}}}}}}}}}}}, bson.D{bson.E{Key:"$group", Value:bson.D{bson.E{Key:"_id", Value:interface {}(nil)}, bson.E{Key:"count", Value:bson.D{bson.E{Key:"$sum", Value:1}}}}}}}
pipeline = aggregation.StageBsonBuilder().
Match(or).
Group(nil, aggregation.Sum("count", 1)...).Build()
fmt.Printf("%#v\n\n", pipeline)
// mongo.Pipeline{bson.D{bson.E{Key:"$unwind", Value:"$size"}}}
pipeline = aggregation.StageBsonBuilder().Unwind("$size", nil).Build()
fmt.Printf("%#v\n\n", pipeline)
// mongo.Pipeline{bson.D{bson.E{Key:"$unwind", Value:bson.D{bson.E{Key:"path", Value:"$size"}, bson.E{Key:"includeArrayIndex", Value:"arrayIndex"}, bson.E{Key:"preserveNullAndEmptyArrays", Value:true}}}}}
pipeline = aggregation.StageBsonBuilder().Unwind("$size", &types.UnWindOptions{
IncludeArrayIndex: "arrayIndex",
PreserveNullAndEmptyArrays: true,
}).Build()
fmt.Printf("%#v", pipeline)
}
aggregation 包提供的方法不止这些,以上只是列举出一些典型的例子,还有更多的用法等着你去探索。
小结
本文对 go-mongox 框架进行了详细的介绍,它有两个核心,一个是基于泛型的 colletion 形态,另一个就是 bson 构造器了。这两个核心是单独存在的,你可以使用其中之一,也可以同时使用。
仓库地址:github.com/chenmingyong0423/go-mon...
该框架处于初期阶段,希望通过集思广益的方式,邀请各位开发者共同参与,提出宝贵的建议和意见,共同打造一个更强大、更灵活的框架。期待着您的积极参与和宝贵反馈,共同推动
go-mongox不断进步。
本作品采用《CC 协议》,转载必须注明作者和本文链接

关于 LearnKu
推荐文章: