Go语言搬砖 操作mongodb

2,011 阅读4分钟

这是我参与8月更文挑战的第23天,活动详情查看:8月更文挑战

简介

MongoDB是一个通用的,基于文档的分布式数据库,基于文档,既类似于JSON的文档内存储数据,所以非常适合处理json数据以及NoSQL型的日志数据

前几天刚刚发布了5.0.2版本,是一个新的大版本,更新了一大波功能,但比较可惜Robo3T这个工具目前只支持到4.2,所以这里依然以4.2版本为例

术语清晰表

Mongo术语说明SQL术语说明
database数据库database数据库
collection集合table
document文档row
field字段column
index索引index索引
primary key主键(id为主键)primary key主键(自定义自增)

安装

使用docker快速安装,往期传送门: juejin.cn/post/684490…

如果不想开启认证,将--auth参数 删除既可

docker run -itd --name mongo  -p 27017:27017 mongo:4.2.6 --auth

笔者使用的GUI工具是Robo3T robomongo.org/download 现在下载需要输入邮箱信息,以前是不要的,如果介意的同学,可以找找以前的版本

image.png

客户端

基于go的mongo客户端,官方亲自下场了,且在github达到了6k星星,看来应该非常不错的了,

客户端地址: github.com/mongodb/mon…

要求是go大于1.10版本,mongodb2.6以上版本,现在的go都1.17了,不过博主目前用的1.16还没有升级。。

至于客户端对应的兼容性,目前最新的go driver是1.7版本,是支持mongo5.0的

官网说明: docs.mongodb.com/drivers/go/

api例子

初始化

将client和err定义全局变量,函数会经常用的,在项目启动检查连接状态,后续专注业务代码既可

var (
   client *mongo.Client
   err   error
   ctx = context.Background()
)

func init() {
   //ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
   // //defer cancel()
   //连接mongodb
   client, err = mongo.Connect(ctx, options.Client().ApplyURI("mongodb://ip:27017"))
   if err != nil {
      log.Fatalln("mongodb连接错误: ", err)
   }
   //连接检查
   err = client.Ping(ctx,readpref.Primary())
   if err != nil {
      log.Fatalln("mongodb检查失败: ",err)
   }
}

库和表结构

在mongo中,数据库名称和表都无须提前创建,因为mongo里面的数据都是bson对象,没有表结构一说,在写入数据时,就是把将库和表(如果没有)就直接创建了

bson

在go操作mongo的过程中,有一个模块在数据CURD中用来解码值,就是bson。

在mongo中的bson是一种数据格式,在go的客户端是具体实现mongo数据解析和加解码的工具包,有四种类型数据结构:

  • bson.A{} 数组结构 是bson.D的数组类型
  • bson.D{} k/v结构 {"name":"张三"}
  • bson.M{} map结构 {{"name","李四"},{"age",1}}
  • bson.E{} 是bson.D的bson元素,通常在bson.D{}里面使用

image.png

插入数据

插入单条数据

操作集合,拿到collection就可以。可以明显看出bson.M用起来更舒服一点

func insertOne() {
   collection := client.Database("dev").Collection("person")
   one, _ := collection.InsertOne(ctx, bson.M{"name": "法外狂徒张三", "age": 66})
   one2, _ := collection.InsertOne(ctx, bson.D{{"name", "律政大享李三"}, {"age", 26}})

   fmt.Println(one.InsertedID, one2.InsertedID)
   _ = client.Disconnect(ctx)
}

插入多条数据

声明一个切片数据,调用InsertMany方法

这里可以看到InsertOne和InsertMany需要传入的参数都是一样的,在方法内部其实是有一个判断的区别

func insertMany() {
   documents := []interface{}{
      bson.M{"name":"精英律师王五","age":22},
      bson.M{"name":"泼皮无赖赵六","age":23},
   }
   collection := client.Database("dev").Collection("person")
   many, _ := collection.InsertMany(ctx,documents)
   fmt.Println(many.InsertedIDs)
   _ = client.Disconnect(ctx)

}

更新数据

在前面插入数据 把律政大享李三写错名字。。这里更新一下,弄成李四

更新方法需要2个参数,1个过滤条件,1个更新条件

官方例子 其实还加了个ops参数: options.Update().SetUpsert(true) 该参数的意思 如果没有根据fileter查询到结果,就作为新数据插入其中

func updateOne() {
   filter := bson.D{{"name","律政大享李三"}}
   update := bson.D{{"$set",bson.D{{"name","律政大享李四"}}}}
   collection := client.Database("dev").Collection("person")
   one, _ := collection.UpdateOne(ctx, filter, update)
   fmt.Println(one.UpsertedCount)
   _ = client.Disconnect(ctx)
}

现在看一下数据库时面的数据

image.png

查询数据

查询1条数据

查询需要传入1个过滤条件, 条件允许为空,直接返回第一条记录

空: bson.M{}

func findOne() {
   filter := bson.M{"age":66}
   collection := client.Database("dev").Collection("person")
   one,_ := collection.FindOne(ctx, filter).DecodeBytes()
   fmt.Println(one)
}

查询多条数据

默认是按照集合的数据先后进行输出,如果想改变加参数既可,数据条数也是一样,会输出全部,可以使用limit参数控制

func findMany()  {
   //设置排序
   //opts := options.Find().SetSort(bson.D{{"age", 1}})
   //设置返回结果条数
   //options.Find().SetLimit(10)

   collection := client.Database("dev").Collection("person")
   find, _ := collection.Find(ctx, bson.M{})
   var results []bson.M
   _ = find.All(ctx, &results)
   for _,result := range results {
      fmt.Println(result)
   }
}

统计数据

统计该集合所有数据总数

func count() {
   collection := client.Database("dev").Collection("person")
   documents, _ := collection.CountDocuments(ctx, bson.M{})
   fmt.Println(documents)
}

删除数据

如果删除filter是字符串。可以设置忽略大小写 ops := options.Delete().SetCollation(&options.Collation{CaseLevel: false})

删除一条

func deleteOne() {
   collection := client.Database("dev").Collection("person")
   one, _ := collection.DeleteOne(ctx, bson.M{"age": 22})
   fmt.Println(one.DeletedCount)
}

删除多条

如果过滤条件为空,那么将直接清空整个集群

func deleteMany() {
   collection := client.Database("dev").Collection("person")
   many, _ := collection.DeleteMany(ctx, bson.M{})
   fmt.Println(many.DeletedCount)
}

总结

简单的练习了一下官方客户端的使用,较为高级和深入没有涉及,基本上的方法官方都给了例子,mongodb常用来做日志数据存储,地理位置信息存储等,可以基于以构建属于自已公司的日志系统