使用GoLang操作MongoDB
获取包
go get go.mongodb.org/mongo-driver/mongo
go mod vendor
连接数据库
func main() {
var (
client *mongo.Client
err error
db *mongo.Database
collection *mongo.Colllection
)
// 建立连接
if client, err = mongo.Connect(context.TODO(), options.Client().ApplyURI("mongodb://localhost:27017").SetConnecTimeout(5*time.Second)); err != nil {
fmt.Print(err)
return
}
// 选择数据库 my_db
db = client.Database("my_db")
// 选择表
collection = db.Collection("my_collection")
}
将连接到 mongoDB的函数抽出
package util
import (
"log"
"context"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
var mgoCli *mongo.Client
func initEngine() {
var err error
clientOptions := options.Client().ApplyURI("mongodb://localhost:27017")
// 连接到MongoDB
mgoCli, err = mongo.Connect(context.TODO(), clientOptions)
if err != nil {
log.Fatal(err)
}
// 检查连接
err = mgoCli.Ping(context.TODO(), nil)
if err != nil {
log.Fatal(err)
}
}
func GetMgoCli() *mongo.Client {
if mgoCli == nil {
iniEngine()
}
return mgoCli
}
package main
import (
"fmt"
"time"
"context"
"myProject/mongodb/util"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
func main() {
var (
client = util.GetMgoCli()
db *mongo.Databse
collection *mongo.Collection
)
db = client.Database("my_db")
collection = db.Collection("my_cliection")
}
插入一条数据
// 先构建几个结构体
package model
type TimePorint struct {
StartTime int64 `bson:"startTime"` // 开始时间
EndTime int64 `bson:"endTime"` // 结束时间
}
type LogRecord struct {
JobName string `bson:"jobName"` // 任务名
Command string `bson:"command"` // shell 命令
Err string `bson:"err"` // 脚本错误
Content string `bson:"content"` // 脚本输出
Tp TimePorint // 执行时间
}
// main 函数
package main
import (
"fmt"
"context"
"myObject/mongodb/util"
"myObject/mongodb/model"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/bson/primitive"
)
func main() {
var (
client = util.GetMgoCli()
err error
collection *mongo.Collection
lr *model.LogRecord
iResult *mongo.InsertOneResult
id primitive.ObjectID
)
// 选择数据库 my_db 里的表
collection = client.Database("my_db").Collection("my_collection")
// 插入一条数据
if iResult, err = collection.InsertOne(context.TODO(), lr); err != nil {
fmt.Print(err)
return
}
// 默认生成一个全局唯一ID
id = iResult.InsertedID(primitive.objectID)
fmt.Println("自增ID", id.Hex())
}
批量插入数据
package main
import (
"fmt"
"log"
"time"
"context"
"myObject/mongodb/util"
"myObject/mongodb/model"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/bson/primitive"
)
func main() {
var (
client = util.GetMgoCli()
err error
collection *mongo.Collection
result *mongo.InsertManyResult
id primitive.ObjectID
)
collection = client.Database("my_db").Collection("test")
// 批量插入
result, err = collection.InsertMany(context.TODO(), []interface{}{
model.LogRecord{
JobName: "job10",
Command: "echo 1",
Err: "",
Content: "1",
Tp: model.TimePorint{
StartTime: time.Now().Unix(),
EndTime: time.Now().Unix() + 10
},
},
model.LogRecord{
JobName: "job20",
Command: "echo 2",
Err: "",
Content: "2",
Tp: model.TimePorint{
StartTime: time.Now().Unix(),
EndTime: time.Now().Unix() +10,
},
},
})
if err != nil {
log.Fatal(err)
}
if result == nil {
log.Fatal("result nil")
}
for _, v := range result.InsertedIDs {
id = v.(primittive.ObjectID)
fmt.Println("自增ID", id.Hex())
}
}
查询数据
// 添加一个查询结构体
type FindByJobName struct {
JobName string `bson:"jobName"`
}
package main
import (
"fmt"
"context"
"myObject/mongodb/util"
"myObject/mongodb/model"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
func main() {
var (
client = util.GetMgoCli()
err error
collection *mongo.Collection
cursor *mongo.Cursor
)
collection = client.Databse("my_db").Collection("test")
cond := model.FindByJobName{JobName: "job10"}
if cursor, err = collection.Find(context.TODO(), cond, options.Find().Setskip(0), options.Find().SetLimit(2)); err != {
fmt.Println(err)
return
}
for cursor.Next(context.TODO()) {
var lr model.LogRecord
if cursor.Decode(&lr) != nil {
fmt.Print(err)
return
}
fmt.Println(lr)
}
// 这里的结果遍历可以使用另外一种更方便的方式
var results []model.LogRecord
if err = cursor.All(context.TODO(), &results); err != nil {
log.Fatal(err)
}
for _, result := range results {
fmt.Println(result)
}
}
BJSON
使用文档前面的方法进行查询显然是很麻烦的,我们不可能每次查询都定义一个新的struct,是否有一种通用的struct来帮助我们作为过滤条件呢,这时候就需要使用到BSON包。
MongoDB中的JSON文档存储在名为BSON的二进制表示中。与其他JSON数据存储为简单字符串和数字的数据库不同,BSON编码扩展了JSON表示,使其包含额外的类型,如int,long,date,浮点数和decimal128。这使得应用程序更容易可靠的处理,排序和比较数据。
连接MongoDB的Go驱动程序中有两大类型表示BSON数据:D 和 Raw
类型 D 家族被用来简洁的构建使用本地Go类型的BSON对象。这对于构造传递给MongoDB的命令特别有用,D 家族包括四类:
- D: 一个BSON文档,这种类型应该在顺序重要的情况下使用。
- M: 一张无序的map。它和D是一样的,只是它不保持顺序。
- A: 一个BSON数组
- E: D里面的一个元素
使用BSON可以更方便的使用Golang完成对数据库的CURD操作
要使用BSON需要先导入包:
import "go.mongodb.org/mongo-driver/bson"
下面是一个使用D类型构建的过滤器文档的例子,它可以用来查找name字段与'张三'或者'李四'匹配的文档。
bson.D{{
"name",
bson.D{{
"&in",
bson.A{"张三", "李四"}
}}
}}
Raw 类型用于验证字节切片。你还可以使用 Lookup() 从原始类型检索 单个元素。如果你不想要将BSON反序列化成另一种类型的开销,那么这是非常有用的。
那么如何使用这样的方式进行查询呢?
package main
import (
"fmt"
"log"
"context"
"myObject/mongodb/util"
"myObject/mongodb/model"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
func main() {
var (
err error
cursor *mongo.Cursor
client = util.GetMgoCli()
collection *mongo.Collection
)
collection = client.Database("my_db").Collection("test")
filter := bson.M{"jobName": "job10"}
if cursor, err = collection.Find(context.TODO(), filter, options.Find().SetSkip(0), options.Find().SetLimit(2)); err != nil {
log.Fatal(err)
}
// 延迟关闭游标
defer func() {
if err = cursor.Close(context.TODO()); err != nil {
log.Fatal(err)
}
}()
var result []model.LogRecord
if err = cursor.All(context.TODO(), &results); err != nil {
log.Fatal(err)
}
for _, result := range results {
fmt.Println(result)
}
}
聚合查询
有时候我们需要对数据进行聚合查询,那么就要用到group等聚合方法
package main
import (
"fmt"
"log"
"context"
"myObject/mongodb/util"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
)
func main() {
var (
err error
cursor *mongo.Cursor
client = util.GetMgoCli()
collection *mongo.Collection
)
collection = client.Database("my_db").Collection("test")
groupStatge := mongo.Pipeline{bson.D{
{"$group", bson.D{
{"_id", "$jobName"},
{"countJob", bson.D{
{"$sum", 1}
}},
}},
}}
if cursor, err = collection.Aggregate(context.TODO(), groupStage,); err != nil {
log.Fatal(err)
}
// 延迟关闭游标
defer func() {
if err = cursor.Close(context.TODO()); err != nil {
log.Fatal(err)
}
}()
// 遍历游标
var results []bson.M
if err = cursor.All(context.TODO(), &results); err != nil {
log.Fatal(err)
}
for _, result := range results {
fmt.Println(result)
}
}
更新数据
同样的,使用 mongo-go-driver 进行更新也需要建立专门用于更新的实体,在这里我们建立的实体中存在 Command, Content 两个字段,更新时需要同时对这两个字段进行赋值,否则未被赋值的字段会被更新为goland的数据类型初始值。为更新方便可以采用 bson.M{"$set": bson.M{"command": "ByBson",}} 来进行更新
package model
// 更新实体
type UpdateByJobName struct {
Command string `bson:"command"`
Content string `bson:"content"`
}
package main
import (
"log"
"context"
"myObject/mongodb/util"
"myObject/mongodb/mooel"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
)
func main () {
var (
err error
client = util.GetMgoCli()
collection *mongo.Collection
uResult *mongo.UpdateResult
)
collection = client.Database("my_db").Colllection("test")
filter := bson.M{"jobName": "job10"}
update := bson.M{"$set": model.UpdateByJobName{Command: "byModel", Content: "model"}}
if uResult, err = collection.UpdateMany(context.TODO(), filter, update); err != nil {
log.Fatal(err)
}
log.Println(uResult.MatchedCount)
}
bson.M{"$set": model.UpdateByJobName{Command: "byModel", Content: "model"}}
中的 $set
表示修改字段的值。
使用$inc
可以对字段的值进行增减计算,例如bson.M{"$inc": bson.M{"age": -1,}}
表示对age减1。
使用$push
可以对该字段增加一个元素,例如 bson.M{"$push": bson.M{"interests": "Golang",}}
表示对interests字段的元素数组增加Golang元素。
使用 $push
可以对该字段删除一个元素,例如 bson.M{"$pull": bson.M{"interests": "Golang",}}
表示对interests字段的元素数组删除Golang元素。
删除数据
package main
import (
"log"
"context"
"myObject/mongodb/util"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
)
func main() {
var (
err error
client = util.GetMgoCli()
collection *mongo.Collection
uResult *mongo.DeleteResult
)
collection = client.Database("my_db").Collection("test")
filter := bson.M{"jobName": "job0"}
if uResult, err = collection.DeleteMany(context.TODO(), filter); err != nil {
log.Fatal(err)
}
log.Println(uResult.DeletedCount)
}
// 带过滤条件删除
package main
import (
"log"
"time"
"context"
"myObject/mongodb/util"
"go.mongodb.org/mongo-driver/mongo"
)
type DeleteCond struct {
BeforeCond TimeBeforeCond `bson:"tp.startTime"`
}
// startTime小于某个时间,使用这种方式可以对想要进行的操作($set, $group)提前定义
type TimeBeforeCond struct {
BeforeTime int64 `bson:"$lt"`
}
func main() {
var (
err error
delCond *DeleteCond
client = util.GetMgoCli()
collection *mongo.Collection
uResult *mongo.DeleteResult
)
collection = client.Database("my_db").Collection("test")
delCond = &DeleteCond{BeforeCond: TimeBeforeCond{BeforeTime: time.Now().Unix()}}
if uResult, err = collection.DeleteMany(context.TODO(), delCond); err != nil {
log.Fatal(err)
}
log.Println(uResult.DeletedCount)
}
最终使用的过滤方式
package model
type TimePorintFilter struct {
StartTime interface{} `bson:"tp.startTime,omitempty"` // 开始时间
EndTime interface{} `bson:"tp.endTime,omitempty"` // 结束时间
}
type LogRecordFilter struct {
ID interface{} `bson:"_id,omitempty"`
JobName interface{} `bson:"jobName,omitempty" json:"jobName"` // 任务名称
Command interface{} `bson:"command,omitempty"` // shell命令
Err interface{} `bson:"err,omitempty"` // 脚本错误
Content interface{} `bson:"content,omitempty"` // 脚本输出
Tp interface{} `bson:"tp,omitempty"` // 执行时间
}
// 小于
type Lt struct {
Lt int64 `bson:"$lt"`
}
// 分组
type Group struct {
Group interface{} `bson:"$group"`
}
// 求和
type Sum struct {
Sum interface{} `bson:"$sum"`
}
package main
import (
"log"
"time"
"context"
"myObject/mongodb/util"
"go.mongodb.org/mongo-driver/mongo"
)
type DeleteCond struct {
BeforeCond TimeBeforeCond `bson:"tp.startTime"`
}
// startTime 小于某个时间
type TimeBeforeCond struct {
BeforeTime int64 `bson:"$lt"`
}
func main() {
var (
client = util.GetMgoCli()
collection *mongo.Collection
err error
uResult *mongo.DeleteResult
delCond *DeleteCond
)
collection = client.Database("my_db").Collection("test")
delCond = &DeleteCond{BeforeCond: TimeBeforeCond{BeforeTime: time.Now().Unix()}}
if uResult, err = collection.DeleteMany(context.TODO(), delCond); err != nil {
log.Fatal(err)
}
log.Println(uResult.DeletedCount)
}
package main
import (
"fmt"
"log"
"context"
"myObject/mongodb/util"
"myObject/mongodb/model"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
)
func main() {
var (
err error
cursor *mongo.Cursor
client = util.GetMgoCli()
collection *mongo.Collection
)
collection = client.Database("my_db").Collection("test")
groupStage := []model.Group{}
groupStage = append(groupStage, model.Group{
Group: bson.D{
{"_id", "$jobName"},
{"countJob", model.Sum{Sum: 1}},
},
})
if cursor, err = collection.Aggregate(context.TODO(), groupStage,); err != nil {
log.Fatal(err)
}
// 延迟关闭
defer func() {
if err = cursor.Close(context.TODO()); err != nil {
log.Fatal(err)
}
}()
var results []bson.M
if err = cursor.All(context.TODO(), &results); err != nil {
log.Fatal(err)
}
for _, result := range results {
fmt.Println(result)
}
}
`
网友评论