Go 中使用Monogo详解

使用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)
  }
}

`

你可能感兴趣的:(Go 中使用Monogo详解)