go-mongox:简单高效,让文档操作和 bson 数据构造更流畅

前言

Go 语言中使用 MongoDB 官方框架进行集合操作时,深深感到构建 bson 数据是一件非常繁琐的工作。字段、逗号,括号等符号的排列,让我感觉仿佛是在进行一场拼图游戏。因此我在想,有没有一个能让我丝滑,高效操作 MongoDB 的第三方框架呢,遗憾的是,并没有找到符合我预期的框架,索性我就自己动手开发了一个,这就是 go-mongox 框架的由来。

如果你也有类似我的这种感受,相信 go-mongox 框架能给你带来不一样的体验。

go-mongox

go-mongox 基于 泛型MongoDB 官方框架进行了二次封装,它通过使用链式调用的方式,让我们能够丝滑地操作文档。同时,其还提供了多种类型的 bson 构造器,帮助我们高效的构建 bson 数据。

仓库地址:github.com/chenmingyon...

该框架处于初期阶段,希望通过集思广益的方式,邀请各位开发者共同参与,提出宝贵的建议和意见,共同打造一个更强大、更灵活的框架。期待着您的积极参与和宝贵反馈,共同推动go-mongox不断进步。

功能

  • 文档的 crud 操作
  • 聚合操作
  • 构造 bson 数据
  • ······(敬请期待)

安装

go get github.com/chenmingyong0423/go-mongox@latest

collection 集合操作

基于泛型的 collection 形态初始化

go 复制代码
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      string `bson:"_id"`
	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 是一个创造器,用于执行插入相关的操作。

插入单个文档

go 复制代码
// 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"

	"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)

	// 插入一个文档
	doc := collection.Post{Id: "1", Title: "go-mongox", Author: "陈明勇", Content: "go-mongox,不一样的体验。"}
	oneResult, err := postCollection.Creator().InsertOne(context.Background(), doc)
	if err != nil {
		panic(err)
	}
	fmt.Println(oneResult.InsertedID.(string) == "1") // true

	// 携带 option 参数
	oneResult, err = postCollection.Creator().OneOptions(options.InsertOne().SetComment("test")).InsertOne(context.Background(), collection.Post{Id: "2", Title: "go 语言 go-mongox 库的使用教程", Author: "陈明勇", Content: "go-mongox 旨在提供更方便和高效的MongoDB数据操作体验。"})
	if err != nil {
		panic(err)
	}
	fmt.Println(oneResult.InsertedID.(string) == "2") // true
}

基于 postCollection 实例,我们可以通过 Creator() 方法创建一个创造器,然后进行插入操作。

InsertOne 方法与官方的 API 同名,作用是插入一条数据。如果我们想要设置 options 参数,应使用 OneOptions 方法。

可以看到,无论是设置 options 参数还是执行插入操作,都在一条链路上完成,即实现了链式操作。

插入多个文档

go 复制代码
// 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)

	docs := []collection.Post{
		{Id: "1", Title: "go", Author: "陈明勇", Content: "..."},
		{Id: "2", Title: "mongo", Author: "陈明勇", Content: "..."},
	}
	manyResult, err := postCollection.Creator().InsertMany(context.Background(), docs)
	if err != nil {
		panic(err)
	}
	fmt.Println(len(manyResult.InsertedIDs) == 2) // true
	// 携带 option 参数
	manyResult, err = postCollection.Creator().ManyOptions(options.InsertMany().SetComment("test")).InsertMany(context.Background(), []collection.Post{
		{Id: "3", Title: "go-mongox", Author: "陈明勇", Content: "..."},
		{Id: "4", Title: "builder", Author: "陈明勇", Content: "..."},
	})
	if err != nil {
		panic(err)
	}
	fmt.Println(len(manyResult.InsertedIDs) == 2) // true
}

InsertMany 方法与官方的 API 同名,作用是插入多条数据。如果我们想要设置 options 参数,应使用 ManyOptions 方法。

Finder 查询器

Finder 是一个查询器,用于执行查询相关的操作。

查询单个文档

go 复制代码
// 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"

	"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() {
	// 你需要预先创建一个 *mongo.Collection 对象
	mongoCollection := collection.NewCollection()
	// 使用 Post 结构体作为泛型参数创建一个 collection
	postCollection := mongox.NewCollection[collection.Post](mongoCollection)
	_, err := postCollection.Creator().InsertOne(context.Background(), collection.Post{Id: "1", Title: "go", Author: "陈明勇", Content: "..."})
	if err != nil {
		panic(err)
	}
	// 查询单个文档
	post, err := postCollection.Finder().Filter(bsonx.Id("1")).FindOne(context.Background())
	if err != nil {
		panic(err)
	}
	fmt.Println(post)

	// 设置 *options.FindOneOptions 参数
	post2, err := postCollection.Finder().
		Filter(bsonx.Id("1")).
		OneOptions(options.FindOne().SetProjection(bsonx.M("content", 0))).
		FindOne(context.Background())
	if err != nil {
		panic(err)
	}
	fmt.Println(post2)

	// - map 作为 filter 条件
	post3, err := postCollection.Finder().Filter(map[string]any{"_id": "1"}).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").Eq("author", "陈明勇").Build()).
		FindOne(context.Background())
	if err != nil {
		panic(err)
	}
	fmt.Println(post4)
}

基于 postCollection 实例,我们可以通过 Finder() 方法创建一个查询器,然后进行查询操作。

FindOne 方法与官方的 API 同名,作用是查询单个文档。我们可以通过 FilterOneOptions 方法分别设置 查询条件options 参数。

对于简单的查询条件,我们可以使用 bsonx 包提供的函数进行构造,例如 bsonx.Id("1");对于复杂的查询条件,我们可以使用 query 包提供的 BsonBuilder构造器进行构造。这两个包的用法接下来会进行详细地介绍。

查询多个文档

go 复制代码
// 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() {
	// 你需要预先创建一个 *mongo.Collection 对象
	mongoCollection := collection.NewCollection()
	// 使用 Post 结构体作为泛型参数创建一个 collection
	postCollection := mongox.NewCollection[collection.Post](mongoCollection)
	_, err := postCollection.Creator().InsertMany(context.Background(), []collection.Post{
		{Id: "1", Title: "go", Author: "陈明勇", Content: "..."},
		{Id: "2", Title: "mongo", Author: "陈明勇", Content: "..."},
	})
	if err != nil {
		panic(err)
	}

	// 查询多个文档
	// bson.D{bson.E{Key: "_id", Value: bson.M{"$in": []string{"1", "2"}}}}
	posts, err := postCollection.Finder().Filter(query.BsonBuilder().InString("_id", []string{"1", "2"}...).Build()).Find(context.Background())
	if err != nil {
		panic(err)
	}
	for _, post := range posts {
		fmt.Println(post)
	}

	// 设置 *options.FindOptions 参数
	// bson.D{bson.E{Key: "_id", Value: bson.M{types.In: []string{"1", "2"}}}}
	posts2, err := postCollection.Finder().
		Filter(query.BsonBuilder().InString("_id", []string{"1", "2"}...).Build()).
		Options(options.Find().SetProjection(bsonx.M("content", 0))).
		Find(context.Background())
	if err != nil {
		panic(err)
	}
	for _, post := range posts2 {
		fmt.Println(post)
	}
}

Find 方法与官方的 API 同名,作用是查询多个文档。如果我们想要设置 options 参数,应使用 Options 方法。

在上面的例子中,为了构造 $in 查询语句,我们使用了 BsonBuilder 提供的方法 InString

Updater 更新器

Updater 是一个更新器,用于执行更新相关的操作。

更新单个文档

go 复制代码
// 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"

	"github.com/chenmingyong0423/go-mongox"
	"github.com/chenmingyong0423/go-mongox/bsonx"
	"github.com/chenmingyong0423/go-mongox/builder/update"
	"github.com/chenmingyong0423/go-mongox/types"
	"go.mongodb.org/mongo-driver/mongo/options"
)

func main() {
	// 你需要预先创建一个 *mongo.Collection 对象
	mongoCollection := collection.NewCollection()
	// 使用 Post 结构体作为泛型参数创建一个 collection
	postCollection := mongox.NewCollection[collection.Post](mongoCollection)
	_, err := postCollection.Creator().InsertOne(context.Background(), collection.Post{Id: "1", Title: "go", Author: "陈明勇", Content: "..."})
	if err != nil {
		panic(err)
	}

	// 更新单个文档
	// 通过 update 包构建 bson 更新语句
	updateResult, err := postCollection.Updater().
		Filter(bsonx.Id("1")).
		Updates(update.BsonBuilder().Set(bsonx.M("title", "golang")).Build()).
		UpdateOne(context.Background())
	if err != nil {
		panic(err)
	}
	fmt.Println(updateResult.ModifiedCount == 1) // true

	// - 使用 map 构造更新数据,并设置 *options.UpdateOptions,执行 upsert 操作
	updateResult2, err := postCollection.Updater().
		Filter(bsonx.Id("2")).
		UpdatesWithOperator(types.Set, map[string]any{"title": "mongo"}).Options(options.Update().SetUpsert(true)).
		UpdateOne(context.Background())
	if err != nil {
		panic(err)
	}
	fmt.Println(updateResult2.UpsertedID.(string) == "2") // true
}

基于 postCollection 实例,我们可以通过 Updater() 方法创建一个更新器,然后进行更新操作。

UpdateOne 方法与官方的 API 同名,作用是更新单个文档。我们可以通过 FilterOptions 方法分别设置 文档匹配的条件options 参数。

对于更新操作参数,我们可以使用以下两个方法进行设置:

  • Updates 方法:该方法接收 bsonmap 等合法的更新操作语句。上面的例子使用了 update 包里的 BsonBuilder 对更新操作语句进行构造。
  • UpdatesWithOperator 方法:该方法的第一个参数为更新操作符,第二个参数为预期更新的数据。

更新多个文档

go 复制代码
// 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/bsonx"
	"github.com/chenmingyong0423/go-mongox/builder/query"
	"github.com/chenmingyong0423/go-mongox/builder/update"
)

func main() {
	// 你需要预先创建一个 *mongo.Collection 对象
	mongoCollection := collection.NewCollection()
	// 使用 Post 结构体作为泛型参数创建一个 collection
	postCollection := mongox.NewCollection[collection.Post](mongoCollection)
	_, err := postCollection.Creator().InsertMany(context.Background(), []collection.Post{
		{Id: "1", Title: "go", Author: "陈明勇", Content: "..."},
		{Id: "2", Title: "mongo", Author: "陈明勇", Content: "..."},
	})
	if err != nil {
		panic(err)
	}

	// 更新多个文档
	updateResult, err := postCollection.Updater().
		Filter(query.BsonBuilder().InString("_id", []string{"1", "2"}...).Build()).
		Updates(update.BsonBuilder().Set(bsonx.M("title", "golang")).Build()).
		UpdateMany(context.Background())
	if err != nil {
		panic(err)
	}
	fmt.Println(updateResult.ModifiedCount == 2) // true
}

UpdateMany 方法与官方的 API 同名,作用是更新多个文档。

Deleter 删除器

Deleter 是一个删除器,用于执行删除相关的操作。

删除单个文档

go 复制代码
// 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"
	"github.com/chenmingyong0423/go-mongox/bsonx"
	"go.mongodb.org/mongo-driver/mongo/options"
)

func main() {
	// 你需要预先创建一个 *mongo.Collection 对象
	mongoCollection := collection.NewCollection()
	// 使用 Post 结构体作为泛型参数创建一个 collection
	postCollection := mongox.NewCollection[collection.Post](mongoCollection)
	_, err := postCollection.Creator().InsertMany(context.Background(), []collection.Post{
		{Id: "1", Title: "go", Author: "陈明勇", Content: "..."},
		{Id: "2", Title: "mongo", Author: "陈明勇", Content: "..."},
	})
	if err != nil {
		panic(err)
	}

	// 删除单个文档
	deleteResult, err := postCollection.Deleter().Filter(bsonx.Id("1")).DeleteOne(context.Background())
	if err != nil {
		panic(err)
	}
	fmt.Println(deleteResult.DeletedCount == 1) // true

	// 携带 option 参数
	deleteResult2, err := postCollection.Deleter().Filter(bsonx.Id("2")).Options(options.Delete().SetComment("test")).DeleteOne(context.Background())
	if err != nil {
		panic(err)
	}
	fmt.Println(deleteResult2.DeletedCount == 1) // true
}

基于 postCollection 实例,我们可以通过 Deleter() 方法创建一个删除器,然后进行删除操作。

DeleteOne 方法与官方的 API 同名,作用是删除单个文档。我们可以通过 FilterOptions 方法分别设置 文档匹配的条件options 参数。

删除多个文档

go 复制代码
// 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() {
    // 你需要预先创建一个 *mongo.Collection 对象
    mongoCollection := collection.NewCollection()
    // 使用 Post 结构体作为泛型参数创建一个 collection
    postCollection := mongox.NewCollection[collection.Post](mongoCollection)
    _, err := postCollection.Creator().InsertMany(context.Background(), []collection.Post{
       {Id: "1", Title: "go", Author: "陈明勇", Content: "..."},
       {Id: "2", Title: "mongo", Author: "陈明勇", Content: "..."},
    })
    if err != nil {
       panic(err)
    }

    // 删除多个文档
    // - 通过 query 包构造复杂的 bson 语句
    deleteResult, err := postCollection.Deleter().Filter(query.BsonBuilder().InString("_id", []string{"1", "2"}...).Build()).DeleteMany(context.Background())
    if err != nil {
       panic(err)
    }
    fmt.Println(deleteResult.DeletedCount == 2) // true
}

DeleteMany 方法与官方的 API 同名,作用是删除多个文档。

Aggregator 聚合器

Aggregator 是一个聚合器,用于执行聚合相关的操作。

go 复制代码
// 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"
	"github.com/chenmingyong0423/go-mongox/types"
	"go.mongodb.org/mongo-driver/mongo"
)

func main() {
	// 你需要预先创建一个 *mongo.Collection 对象
	mongoCollection := collection.NewCollection()
	// 使用 Post 结构体作为泛型参数创建一个 collection
	postCollection := mongox.NewCollection[collection.Post](mongoCollection)
	_, err := postCollection.Creator().InsertMany(context.Background(), []collection.Post{
		{Id: "1", Title: "go", Author: "陈明勇", Content: "..."},
		{Id: "2", Title: "mongo", Author: "陈明勇", Content: "..."},
	})
	if err != nil {
		panic(err)
	}

	// 聚合操作
	// - 使用 aggregation 包构造 pipeline
	posts, err := postCollection.
		Aggregator().Pipeline(aggregation.StageBsonBuilder().Project(bsonx.M("content", 0)).Build()).
		Aggregate(context.Background())
	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.D(types.KV("name", "$author"), types.KV("author", 1), types.KV("_id", 1), types.KV("title", 1), types.KV("outstanding", aggregation.BsonBuilder().Eq("$author", "陈明勇").Build()))).Build(),
		).
		AggregateWithCallback(context.Background(), func(ctx context.Context, cursor *mongo.Cursor) error {
			return cursor.All(ctx, &result)
		})

	for _, post := range result {
		fmt.Println(post)
	}
}

基于 postCollection 实例,我们可以通过 Aggregator() 方法创建一个聚合器,然后进行聚合操作。

我们可以通过 PipelineAggregateOptions 方法分别设置 pipelineoptions 参数。

对于执行聚合操作,有以下两个方法:

  • Aggregate 方法:与与官方的 API 同名。
  • AggregateWithCallback 方法:因为我们在创建 collection 装饰器时,使用泛型绑定了一个结构体,如果我们执行聚合操作之后,返回的数据与所绑定的结构体映射不上,这时可以使用该方法将结果映射到指定的结构里。

Builder 构造器

go-mongox 框架提供了以下几种类型的构造器:

  • universal: 简单而又通用的 bson 数据构造函数。
  • query: 查询构造器,用于构造查询操作所需的 bson 数据。
  • update: 更新构造器,用于构造更新操作所需的 bson 数据。
  • aggregation: 聚合操作构造器,包含两种,一种是用于构造聚合 stage 阶段所需的 bson 数据,另一种是用于构造除了 stage 阶段以外的 bson 数据。

universal 通用构造

我们可以使用 bsonx 包里的一些函数进行 bson 数据的构造,例如 bsonx.Mbsonx.Idbsonx.D 等等。

go 复制代码
// 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.D{bson.E{Key:"姓名", Value:"陈明勇"}, bson.E{Key:"手机号", Value:"1888***1234"}}
	d := bsonx.D(bsonx.KV("姓名", "陈明勇"), bsonx.KV("手机号", "1888***1234"))
	fmt.Printf("%#v\n\n", d)

	// bson.E{Key:"姓名", Value:"陈明勇"}
	e := bsonx.E("姓名", "陈明勇")
	fmt.Printf("%#v\n\n", e)

	// bson.A{"陈明勇", "1888***1234"}
	a := bsonx.A("陈明勇", "1888***1234")
	fmt.Printf("%#v", a)
}

bsonx 包暂时提供了这些构造函数,后面会持续添加更多有用的函数。

特别注意的是,使用 bsonx.D 方法构造数据时,传入的参数,需要使用 bsonx.KV 方法进行传递,目的是强约束 key-value 的类型。

query 查询构造器

query 包可以帮我们构造出查询相关的 bson 数据,例如 $in$gt$and 等等。

go 复制代码
// 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:"陈明勇"}}
	d := query.BsonBuilder().Add(bsonx.KV("姓名", "陈明勇")).Build()
	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:"age", Value:bson.D{{Key:"$in", Value:[]int{18, 19, 20}}}}}
	d = query.BsonBuilder().InInt("age", 18, 19, 20).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\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.BsonBuilder().ElemMatch("result", bsonx.D(bsonx.KV("$gte", 80), bsonx.KV("$lt", 85))).Build()
	fmt.Printf("%#v", d)
}

query 包提供的方法不止这些,以上只是列举出一些典型的例子,还有更多的用法等着你去探索。

update 更新构造器

update 包可以帮我们构造出更新操作相关的 bson 数据,例如 $set$$inc$push 等等。

go 复制代码
// https://github.com/chenmingyong0423/blog/blob/master/tutorial-code/go-mongox/builder/update.go
package main

import (
	"fmt"

	"github.com/chenmingyong0423/go-mongox/bsonx"
	"github.com/chenmingyong0423/go-mongox/builder/update"
)

func main() {
	// bson.D{bson.E{Key:"$set", Value:bson.M{"name":"陈明勇"}}}
	u := update.BsonBuilder().Set(bsonx.M("name", "陈明勇")).Build()
	fmt.Printf("%#v\n\n", u)

	// bson.D{bson.E{Key:"$inc", Value:bson.D{bson.E{Key:"orders", Value:1}, bson.E{Key:"ratings", Value:-1}}}}
	u = update.BsonBuilder().Inc(bsonx.D(bsonx.KV("orders", 1), bsonx.KV("ratings", -1))).Build()
	fmt.Printf("%#v\n\n", u)

	// bson.D{bson.E{Key:"$push", Value:bson.M{"scores":95}}}
	u = update.BsonBuilder().Push(bsonx.M("scores", 95)).Build()
	fmt.Printf("%#v\n\n", u)

	// bson.D{bson.E{Key:"$unset", Value:bson.D{primitive.E{Key:"quantity", Value:""}, bson.E{Key:"instock", Value:""}}}}
	u = update.BsonBuilder().Unset("quantity", "instock").Build()
	fmt.Printf("%#v", u)
}

update 包提供的方法不止这些,以上只是列举出一些典型的例子,还有更多的用法等着你去探索。

aggregation 聚合构造器

aggregation 包提供了两个 builder

  • StageBsonBuilder:用于构造 stage 阶段所需的 bson 数据
  • BsonBuilder:用于构造除了 stage 阶段以外的 bson 数据。
go 复制代码
// 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/builder/query"
    "github.com/chenmingyong0423/go-mongox/types"
)

func main() {
    // bson.D{bson.E{Key:"$gt", Value:[]any{"$qty", 250}}}
    gt := aggregation.BsonBuilder().Gt("$qty", 250).Build()
    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:"age", Value:1}, bson.E{Key:"qtyGt250", Value:bson.D{bson.E{Key:"$gt", Value:[]interface {}{"$qty", 250}}}}}}}}
    pipeline := aggregation.StageBsonBuilder().Project(bsonx.D(bsonx.KV("name", 1), bsonx.KV("age", 1), bsonx.KV("qtyGt250", gt))).Build()
    fmt.Printf("%#v\n\n", pipeline)

    // bson.D{bson.E{Key:"$or", Value:[]interface {}{bson.D{bson.E{Key:"score", Value:bson.D{bson.E{Key:"$gt", Value:70}, bson.E{Key:"$lt", Value:90}}}}, bson.D{bson.E{Key:"views", Value:bson.D{bson.E{Key:"$gte", Value:90}}}}}}}
    or := aggregation.BsonBuilder().Or(
       query.BsonBuilder().Gt("score", 70).Lt("score", 90).Build(),
       query.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:"$or", Value:[]any{bson.D{bson.E{Key:"score", Value:bson.D{bson.E{Key:"$gt", Value:70}, bson.E{Key:"$lt", Value:90}}}}, bson.D{bson.E{Key:"views", Value:bson.D{bson.E{Key:"$gte", Value:90}}}}}}}}}, bson.D{bson.E{Key:"$group", Value:bson.D{bson.E{Key:"_id", Value:any(nil)}, bson.E{Key:"count", Value:bson.D{bson.E{Key:"$sum", Value:1}}}}}}}
    pipeline = aggregation.StageBsonBuilder().Match(or).Group(nil, bsonx.E("count", aggregation.BsonBuilder().Sum(1).Build())).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/chenmingyon...

该框架处于初期阶段,希望通过集思广益的方式,邀请各位开发者共同参与,提出宝贵的建议和意见,共同打造一个更强大、更灵活的框架。期待着您的积极参与和宝贵反馈,共同推动go-mongox不断进步。

相关推荐
Ai 编码助手1 小时前
在 Go 语言中如何高效地处理集合
开发语言·后端·golang
小丁爱养花1 小时前
Spring MVC:HTTP 请求的参数传递2.0
java·后端·spring
Channing Lewis2 小时前
什么是 Flask 的蓝图(Blueprint)
后端·python·flask
加酶洗衣粉2 小时前
MongoDB部署模式
数据库·mongodb
我要出家当道士2 小时前
MongoDB 备份与恢复综述
mongodb·数据库灾备
Suyuoa2 小时前
mongoDB常见指令
数据库·mongodb
添砖,加瓦2 小时前
MongoDB详细讲解
数据库·mongodb
我的运维人生2 小时前
MongoDB深度解析与实践案例
数据库·mongodb·运维开发·技术共享
轩辕烨瑾3 小时前
C#语言的区块链
开发语言·后端·golang
栗豆包5 小时前
w175基于springboot的图书管理系统的设计与实现
java·spring boot·后端·spring·tomcat