美文网首页
Go 中使用Monogo详解

Go 中使用Monogo详解

作者: 木叶苍蓝 | 来源:发表于2022-07-28 14:33 被阅读0次

    使用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详解

          本文链接:https://www.haomeiwen.com/subject/pwpzirtx.html