【青训营】Go语言操作MangoDB入门 | 青训营笔记

177 阅读5分钟

MangoDB

这是我参与「第三届青训营 -后端场」笔记创作活动的的第5篇笔记。

对MangoDB的初步学习。

MangoDB介绍

MongoDB is a document database with the scalability and flexibility that you want with the querying and indexing that you need.

mongoDB是目前比较流行的一个基于分布式文件存储的数据库,它是一个介于关系数据库和非关系数据库(NoSQL)之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的。

mongoDB中将一条数据存储为一个文档(document),数据结构由键值(key-value)对组成。 其中文档类似于我们平常编程中用到的JSON对象。 文档中的字段值可以包含其他文档,数组及文档数组。

MongoDB术语/概念说明对比SQL术语/概念
database数据库database
collection集合table
document文档row
field字段column
indexindex索引
primary key主键 MongoDB自动将_id字段设置为主键primary key

MangoDB安装

通过docker安装比较方便。

这里我们以安装MongoDB5.0版本为例。

首先docker pull拉取镜像:

 docker pull mongo:5.0

接下来docker run启动容器:

 docker run -d --name mongodb5 \
 -p 27017:27017 \
 -v /home/root/dockerVolumes/mongo/mongo5.0:/data/db \
 -e MONGO_INITDB_ROOT_USERNAME=root \
 -e MONGO_INITDB_ROOT_PASSWORD=1234 --privileged=true \
 mongo:5.0

参数说明:

  • -d:后台运行容器,并返回容器ID
  • --name mongodb5:为该容器指定名称为mongodb5
  • -p 27017:27017:端口映射(主机(宿主)端口:容器端口),即宿主机开放出27017端口,指向容器内的27017端口
  • -v /home/root/dockerVolumes/mongo/mongo5.0:/data/db:绑定数据卷(/宿主机绝对路径目录:/容器内目录),将容器内的/data/db挂载到宿主机的/home/root/dockerVolumes/mongo/mongo5.0文件夹下
  • -e MONGO_INITDB_ROOT_USERNAME=root:设置环境变量,在这里我们设置MongoDB的root用户
  • -e MONGO_INITDB_ROOT_PASSWORD=1234 --privileged=true:设置环境变量,root用户密码为1234。privileged=true 使得容器内的root拥有真正的root权限

MangoDB使用

MangoDB的使用,玩一玩官网的Getting Started就差不多清楚了。

这里引入一下李文周老师博客的一些内容:

数据库常用命令:

show dbs;:查看数据库

 > show dbs;
 admin   0.000GB
 config  0.000GB
 local   0.000GB
 test    0.000GB

use q1mi;:切换到指定数据库,如果不存在该数据库就创建。

 > use q1mi;
 switched to db q1mi

db;:显示当前所在数据库。

 > db;
 q1mi

db.dropDatabase():删除当前数据库

 > db.dropDatabase();
 { "ok" : 1 }

数据集常用命令:

db.createCollection(name,options):创建数据集

  • name:数据集名称
  • options:可选参数,指定内存大小和索引。
 > db.createCollection("student");
 { "ok" : 1 }

show collections;:查看当前数据库中所有集合。

 > show collections;
 student

db.student.drop():删除指定数据集

 > db.student.drop()
 true

文档常用命令:

插入一条文档:

 > db.student.insertOne({name:"小王子",age:18});
 {
     "acknowledged" : true,
     "insertedId" : ObjectId("5db149e904b33457f8c02509")
 }

插入多条文档:

 > db.student.insertMany([
 ... {name:"张三",age:20},
 ... {name:"李四",age:25}
 ... ]);
 {
     "acknowledged" : true,
     "insertedIds" : [
         ObjectId("5db14c4704b33457f8c0250a"),
         ObjectId("5db14c4704b33457f8c0250b")
     ]
 }

查询所有文档:

 > db.student.find();
 { "_id" : ObjectId("5db149e904b33457f8c02509"), "name" : "小王子", "age" : 18 }
 { "_id" : ObjectId("5db14c4704b33457f8c0250a"), "name" : "张三", "age" : 20 }
 { "_id" : ObjectId("5db14c4704b33457f8c0250b"), "name" : "李四", "age" : 25 }

查询age>20岁的文档:

 > db.student.find(
 ... {age:{$gt:20}}
 ... )
 { "_id" : ObjectId("5db14c4704b33457f8c0250b"), "name" : "李四", "age" : 25 }

更新文档:

 > db.student.update(
 ... {name:"小王子"},
 ... {name:"老王子",age:98}
 ... );
 WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
 > db.student.find()
 { "_id" : ObjectId("5db149e904b33457f8c02509"), "name" : "老王子", "age" : 98 }
 { "_id" : ObjectId("5db14c4704b33457f8c0250a"), "name" : "张三", "age" : 20 }
 { "_id" : ObjectId("5db14c4704b33457f8c0250b"), "name" : "李四", "age" : 25 }

删除文档:

> db.student.deleteOne({name:"李四"});
{ "acknowledged" : true, "deletedCount" : 1 }
> db.student.find()
{ "_id" : ObjectId("5db149e904b33457f8c02509"), "name" : "老王子", "age" : 98 }
{ "_id" : ObjectId("5db14c4704b33457f8c0250a"), "name" : "张三", "age" : 20 }

命令实在太多,更多命令请参阅官方文档:shell命令官方文档:CRUD操作

Go操作MangoDB

mongo的任何操作,包括ConnectCURDDisconnect等都离不开一个操作的上下文Context环境,需要一个Context实例作为操作的第一个参数。

参考下面掘金这篇文章就可以学到很多。遇到有不懂的代码直接Google搜英文,很快就能搞懂。

客户端连接

使用mongo.Connect()函数且带用户名密码认证连接:

package main

import (
	"context"
	"log"

	"go.mongodb.org/mongo-driver/mongo"
	"go.mongodb.org/mongo-driver/mongo/options"
)

func main() {
	// 使用credential可以直接使用带用户名和密码的uri连接
	// clientOpts := options.Client().ApplyURI("mongodb://username:password@localhost:27017")
	credential := options.Credential{
		Username: "root",
		Password: "1234",
	}
	clientOps := options.Client().ApplyURI("mongodb://localhost:27017").SetAuth(credential)
	client, err := mongo.Connect(context.TODO(), clientOps)
	if err != nil {
		log.Fatal(err)
	}  
    // 实例化client后,延迟调用断开连接函数
	defer func() {
		if err = client.Disconnect(ctx); err != nil {
			panic(err)
		}
	}()
}

模块配置式连接

在实际项目中,通常都会有配置模块,因此最常用的连接方式是将连接配置写在专门的配置模块文件中。

首先编写config:

 package config
 ​
 import (
     "time"
 ​
     "go.mongodb.org/mongo-driver/mongo/options"
     "go.mongodb.org/mongo-driver/mongo/readpref"
 )
 ​
 // ClientOpts mongoClient 连接客户端参数
 var ClientOpts = options.Client().
     SetAuth(options.Credential{
         AuthMechanism: "SCRAM-SHA-1",
         //AuthSource:              "anquan",    // 用于身份验证的数据库的名称
         Username: "root",
         Password: "1234",
     }).
     SetConnectTimeout(time.Second * 10).
     SetHosts([]string{"localhost:27017"}).
     SetMaxPoolSize(20).
     SetMinPoolSize(5).
     SetReadPreference(readpref.Primary()). // 默认值是readpref.Primary()(https://www.mongodb.com/docs/manual/core/read-preference/#read-preference)
     SetReplicaSet("")                      // SetReplicaSet指定集群的副本集名称。(默认为空)

有不明确的地方可以点进去看源码,源码中的注释说的非常明确了,以SetReadPreference举例:

 // SetReadPreference specifies the read preference to use for read operations. This can also be set through the
 // following URI options:
 //
 // 1. "readPreference" - Specify the read preference mode (e.g. "readPreference=primary").
 //
 // 2. "readPreferenceTags": Specify one or more read preference tags
 // (e.g. "readPreferenceTags=region:south,datacenter:A").
 //
 // 3. "maxStalenessSeconds" (or "maxStaleness"): Specify a maximum replication lag for reads from secondaries in a
 // replica set (e.g. "maxStalenessSeconds=10").
 //
 // The default is readpref.Primary(). See https://docs.mongodb.com/manual/core/read-preference/#read-preference for
 // more information about read preferences.
 func (c *ClientOptions) SetReadPreference(rp *readpref.ReadPref) *ClientOptions {
 c.ReadPreference = rp
 ​
 return c
 }

然后主模块中引入配置:

package main

import (
   "context"
   "db/nosql/mongodb/demo01/config"
   "log"

   "go.mongodb.org/mongo-driver/mongo"
)

func main() {
   client, err := mongo.Connect(context.TODO(), config.ClientOpts)
   if err != nil {
      log.Fatal(err)
   }
    
   // 实例化client后,延迟调用断开连接函数
   defer func() {
		if err = client.Disconnect(ctx); err != nil {
			panic(err)
		}
	}()
}

CRUD操作

先了解bson

使用mongo-driver操作mongodb需要用到该模块提供的bson。主要用来写查询的筛选条件filter、构造文档记录以及接收查询解码的值,也就是在go与mongo之间做序列化。其中,基本只会用到如下三种数据结构:

  • bson.D{}: 对文档(Document)的有序描述,key-value以逗号,分隔

    如:

    bson.D{{"bame",1}}
    
  • bson.M{}: Map结构,key-value以冒号:分隔无序,使用最方便;

    如:

    bson.M{"name":"虎哥","gender":"男"}
    
  • bson.A{}: 数组结构,元素要求是有序的文档描述,也就是元素是bson.D{}类型。

获取db

package main

import (
	"context"
	"db/nosql/mongodb/demo01/config"
	"fmt"
	"log"
	"time"

	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/mongo"
)

func main() {
	// 对mongo的任何操作,包括Connect、CURD、Disconnect等都离不开一个操作的上下文Context环境,需要一个Context实例作为操作的第一个参数。
	// ctx
	ctx, cancelFunc := context.WithTimeout(context.Background(), time.Second*10)
	defer cancelFunc()

	// client
	client, err := mongo.Connect(context.TODO(), config.ClientOpts)
	if err != nil {
		log.Fatal(err)
	}
	// 实例化client后,延迟调用断开连接函数
	defer func() {
		if err = client.Disconnect(ctx); err != nil {
			panic(err)
		}
	}()

	db := client.Database("test") // 获取名为test的db
	collectionNames, err := db.ListCollectionNames(ctx, bson.M{})
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Println("collectionNames: ", collectionNames)
}

client的连接方式是上面的模块配置式连接。

获取collection

 package main
 ​
 import (
    "context"
    "db/nosql/mongodb/demo01/config"
    "fmt"
    "log"
    "time"
 ​
    "go.mongodb.org/mongo-driver/mongo"
 )
 ​
 func main() {
    // 对mongo的任何操作,包括Connect、CURD、Disconnect等都离不开一个操作的上下文Context环境,需要一个Context实例作为操作的第一个参数。
    // ctx
    ctx, cancelFunc := context.WithTimeout(context.Background(), time.Second*10)
    defer cancelFunc()
 ​
    // client
    client, err := mongo.Connect(context.TODO(), config.ClientOpts)
    if err != nil {
       log.Fatal(err)
    }
    // 实例化client后,延迟调用断开连接函数
    defer func() {
       if err = client.Disconnect(ctx); err != nil {
          panic(err)
       }
    }()
 ​
    db := client.Database("test")         // 获取名为test的db
    collection := db.Collection("person") // 获取collection
    fmt.Println("collection:", collection.Name())
 }

创建索引

 package main
 ​
 import (
    "context"
    "db/nosql/mongodb/demo01/config"
    "fmt"
    "log"
    "time"
 ​
    "go.mongodb.org/mongo-driver/bson"
    "go.mongodb.org/mongo-driver/mongo"
    "go.mongodb.org/mongo-driver/mongo/options"
 )
 ​
 func main() {
    // ctx
    ctx, cancelFunc := context.WithTimeout(context.Background(), time.Second*10)
    defer cancelFunc()
 ​
    // client
    client, err := mongo.Connect(context.TODO(), config.ClientOpts)
    if err != nil {
       log.Fatal(err)
    }
    defer func() {
       if err = client.Disconnect(ctx); err != nil {
          panic(err)
       }
    }()
 ​
    db := client.Database("test")         // 获取名为test的db
    collection := db.Collection("person") // 获取collection
    // 创建索引
    indexView := collection.Indexes()
    indexName := "index_by_name"
    indexBackground := true
    indexUnique := true
    indexModel := mongo.IndexModel{
       Keys: bson.D{{"name", 1}},    // name字段作为索引(1:索引按升序,-1:索引按降序)
       Options: &options.IndexOptions{
          Name:       &indexName,
          Background: &indexBackground,
          Unique:     &indexUnique,
       },
    }
    index, err := indexView.CreateOne(ctx, indexModel)
    if err != nil {
       log.Fatalf("index created failed. err: %v \n", err)
       return
    }
    fmt.Println("new index name:", index)
 }

查看索引

package main

import (
   "context"
   "db/nosql/mongodb/demo01/config"
   "fmt"
   "log"
   "time"

   "go.mongodb.org/mongo-driver/bson"
   "go.mongodb.org/mongo-driver/mongo"
)

func main() {
   // ctx
   ctx, cancelFunc := context.WithTimeout(context.Background(), time.Second*10)
   defer cancelFunc()

   // client
   client, err := mongo.Connect(context.TODO(), config.ClientOpts)
   if err != nil {
      log.Fatal(err)
   }
   defer func() {
      if err = client.Disconnect(ctx); err != nil {
         panic(err)
      }
   }()

   db := client.Database("test")         // 获取名为test的db
   collection := db.Collection("person") // 获取collection
   // 查看索引
   indexCursor, err := collection.Indexes().List(ctx)
   var indexes []bson.M
   if err = indexCursor.All(ctx, &indexes); err != nil {
      log.Fatal(err)
      return
   }
   fmt.Println(indexes)
}

Insert

InsertOne

package main

import (
   "context"
   "db/nosql/mongodb/demo01/config"
   "fmt"
   "log"
   "time"

   "go.mongodb.org/mongo-driver/bson"
   "go.mongodb.org/mongo-driver/mongo"
)

func main() {
   // ctx
   ctx, cancelFunc := context.WithTimeout(context.Background(), time.Second*10)
   defer cancelFunc()

   // client
   client, err := mongo.Connect(context.TODO(), config.ClientOpts)
   if err != nil {
      log.Fatal(err)
   }
   defer func() {
      if err = client.Disconnect(ctx); err != nil {
         panic(err)
      }
   }()

   //db := client.Database("test")         // 获取名为test的db
   //collection := db.Collection("person") // 获取collection
   collection := client.Database("test").Collection("person")
   // InsertOne
   insertOneResult, err := collection.InsertOne(ctx, bson.M{
      "name":   "虎哥",
      "gender": "男",
      "level":  1,
   })
   if err != nil {
      log.Fatal(err)
   }
   fmt.Println("id:", insertOneResult.InsertedID)
   fmt.Println(insertOneResult)
}

InsertMany

package main

import (
   "context"
   "db/nosql/mongodb/demo01/config"
   "fmt"
   "log"
   "time"

   "go.mongodb.org/mongo-driver/bson"
   "go.mongodb.org/mongo-driver/mongo"
   "go.mongodb.org/mongo-driver/mongo/options"
)

func main() {
   // ctx
   ctx, cancelFunc := context.WithTimeout(context.Background(), time.Second*10)
   defer cancelFunc()

   // client
   client, err := mongo.Connect(context.TODO(), config.ClientOpts)
   if err != nil {
      log.Fatal(err)
   }
   defer func() {
      if err = client.Disconnect(ctx); err != nil {
         panic(err)
      }
   }()

   //db := client.Database("test")         // 获取名为test的db
   //collection := db.Collection("person") // 获取collection
   collection := client.Database("test").Collection("person")
   // InsertMany
   docs := []interface{}{
      bson.M{"name": "二次元刀哥", "gender": "男", "level": 0},
      bson.M{"name": "小亮", "gender": "男", "level": 2},
   }
   // Ordered 设置为false表示其中一条插入失败不会影响其他文档的插入,默认为true,一条失败其他都不会被写入
   insertManyOptions := options.InsertMany().SetOrdered(false)
   insertManyResult, err := collection.InsertMany(ctx, docs, insertManyOptions)
   if err != nil {
      log.Fatal(err)
   }
   fmt.Println("ids:", insertManyResult.InsertedIDs)
}

Find

Find

 package main
 ​
 import (
    "context"
    "db/nosql/mongodb/demo01/config"
    "fmt"
    "log"
    "time"
 ​
    "go.mongodb.org/mongo-driver/bson"
    "go.mongodb.org/mongo-driver/mongo"
    "go.mongodb.org/mongo-driver/mongo/options"
 )
 ​
 func main() {
    // ctx
    ctx, cancelFunc := context.WithTimeout(context.Background(), time.Second*10)
    defer cancelFunc()
 ​
    // client
    client, err := mongo.Connect(context.TODO(), config.ClientOpts)
    if err != nil {
       log.Fatal(err)
    }
    defer func() {
       if err = client.Disconnect(ctx); err != nil {
          panic(err)
       }
    }()
 ​
    collection := client.Database("test").Collection("person")
    // Find
    // SetSort 设置排序字段(1表示升序;-1表示降序)
    findOptions := options.Find().SetSort(bson.D{{"level", 1}})
    findCursor, err := collection.Find(ctx, bson.M{"gender": "男"}, findOptions)
    if err != nil {
       log.Fatal(err)
    }
    var results []bson.M
    err = findCursor.All(ctx, &results)
    if err != nil {
       log.Fatal(err)
    }
    for _, result := range results {
       fmt.Println(result)
    }
 }

FindOne

package main

import (
   "context"
   "db/nosql/mongodb/demo01/config"
   "fmt"
   "log"
   "time"

   "go.mongodb.org/mongo-driver/bson"
   "go.mongodb.org/mongo-driver/mongo"
   "go.mongodb.org/mongo-driver/mongo/options"
)

func main() {
   // ctx
   ctx, cancelFunc := context.WithTimeout(context.Background(), time.Second*10)
   defer cancelFunc()

   // client
   client, err := mongo.Connect(context.TODO(), config.ClientOpts)
   if err != nil {
      log.Fatal(err)
   }
   defer func() {
      if err = client.Disconnect(ctx); err != nil {
         panic(err)
      }
   }()

   collection := client.Database("test").Collection("person")
   // FindOne
   // 可以使用struct来接收解码结果
   // var result struct {
   //     Name   string
   //     Gender string
   //     Level  int
   // }

   // 或者更好的是直接使用bson.M
   var result bson.M
   // 按照level排序并跳过第一个, 且只需返回name、gender字段(SetProjection:1表示包含某些字段;0表示不包含某些字段)
   findOneOptions := options.FindOne().SetSkip(1).SetSort(bson.D{{"level", 1}}).SetProjection(bson.D{{"name", 1}, {"gender", 1}})
   singleResult := collection.FindOne(ctx, bson.M{"level": 0}, findOneOptions)
   err = singleResult.Decode(&result)
   if err != nil {
      log.Fatal(err)
   }
   fmt.Println(result)
}

FindOneAndDelete

package main

import (
   "context"
   "db/nosql/mongodb/demo01/config"
   "fmt"
   "log"
   "time"

   "go.mongodb.org/mongo-driver/bson"
   "go.mongodb.org/mongo-driver/mongo"
   "go.mongodb.org/mongo-driver/mongo/options"
)

func main() {
   // ctx
   ctx, cancelFunc := context.WithTimeout(context.Background(), time.Second*10)
   defer cancelFunc()

   // client
   client, err := mongo.Connect(context.TODO(), config.ClientOpts)
   if err != nil {
      log.Fatal(err)
   }
   defer func() {
      if err = client.Disconnect(ctx); err != nil {
         panic(err)
      }
   }()

   collection := client.Database("test").Collection("person")
   // FindOneAndDelete
   findOneAndDeleteOptions := options.FindOneAndDelete().SetProjection(bson.D{{"name", 1}, {"gender", 1}})
   var deleteDocs bson.M
   singleResult := collection.FindOneAndDelete(ctx, bson.M{"name": "胖虎"}, findOneAndDeleteOptions)
   err = singleResult.Decode(&deleteDocs)
   if err != nil {
      log.Fatal(err)
   }
   fmt.Println(deleteDocs)
}

FindOneAndReplace

 package main
 ​
 import (
     "context"
     "db/nosql/mongodb/demo01/config"
     "fmt"
     "log"
     "time"
 ​
     "go.mongodb.org/mongo-driver/bson"
     "go.mongodb.org/mongo-driver/mongo"
     "go.mongodb.org/mongo-driver/mongo/options"
 )
 ​
 func main() {
     // ctx
     ctx, cancelFunc := context.WithTimeout(context.Background(), time.Second*10)
     defer cancelFunc()
 ​
     // client
     client, err := mongo.Connect(context.TODO(), config.ClientOpts)
     if err != nil {
         log.Fatal(err)
     }
     defer func() {
         if err = client.Disconnect(ctx); err != nil {
             panic(err)
         }
     }()
 ​
     collection := client.Database("test").Collection("person")
     // FindOneAndReplace
     // 注意: 返回的是被替换前的document,满足条件的doc将会被完全替换为replacement
     // SetUpsert设置为true:如果没有find到结果,直接插入新结果(默认为false)
     findOneAndReplaceOptions := options.FindOneAndReplace().SetUpsert(true)
     replacement := bson.M{
         "name":  "张三",
         "skill": "打官司",
     }
     var replacePersonDoc bson.M
     err = collection.FindOneAndReplace(ctx, bson.M{"name": "小夫"}, replacement, findOneAndReplaceOptions).Decode(&replacePersonDoc)
     if err != nil {
         log.Fatal(err)
     }
     fmt.Println(replacePersonDoc)
 }

FindOneAndUpdate

 package main
 ​
 import (
    "context"
    "db/nosql/mongodb/demo01/config"
    "fmt"
    "log"
    "time"
 ​
    "go.mongodb.org/mongo-driver/bson"
    "go.mongodb.org/mongo-driver/bson/primitive"
    "go.mongodb.org/mongo-driver/mongo"
    "go.mongodb.org/mongo-driver/mongo/options"
 )
 ​
 func main() {
    // ctx
    ctx, cancelFunc := context.WithTimeout(context.Background(), time.Second*10)
    defer cancelFunc()
 ​
    // client
    client, err := mongo.Connect(context.TODO(), config.ClientOpts)
    if err != nil {
       log.Fatal(err)
    }
    defer func() {
       if err = client.Disconnect(ctx); err != nil {
          panic(err)
       }
    }()
 ​
    collection := client.Database("test").Collection("person")
    // FindOneAndUpdate
    // 注意:返回的结果仍然是更新前的document
    _id, err := primitive.ObjectIDFromHex("62920f38b37f84c93079b7b1") // 从一个十六进制字符串创建一个新的ObjectID
    if err != nil {
       log.Fatal(err)
    }
    findOneAndUpdateOptions := options.FindOneAndUpdate().SetUpsert(true)
    // "$set":Field Update Operators之一。表示更新字段
    update := bson.M{"$set": bson.M{
       "level":  0,
       "gender": "男",
       "msg":    "新的field",
    }}
    var toUpdateDoc bson.M
    err = collection.FindOneAndUpdate(ctx, bson.M{"_id": _id}, update, findOneAndUpdateOptions).Decode(&toUpdateDoc)
    if err != nil {
       log.Fatal(err)
    }
    fmt.Println(toUpdateDoc)
 }
  • FindOneAndReplace:完全替换
  • FindOneAndUpdate:更新指定字段,原有字段会保留

Update

UpdateOne

package main

import (
   "context"
   "db/nosql/mongodb/demo01/config"
   "fmt"
   "log"
   "time"

   "go.mongodb.org/mongo-driver/bson"
   "go.mongodb.org/mongo-driver/mongo"
   "go.mongodb.org/mongo-driver/mongo/options"
)

func main() {
   // ctx
   ctx, cancelFunc := context.WithTimeout(context.Background(), time.Second*10)
   defer cancelFunc()

   // client
   client, err := mongo.Connect(context.TODO(), config.ClientOpts)
   if err != nil {
      log.Fatal(err)
   }
   defer func() {
      if err = client.Disconnect(ctx); err != nil {
         panic(err)
      }
   }()

   collection := client.Database("test").Collection("person")
   // UpdateOne
   updateOptions := options.Update().SetUpsert(true)
   filter := bson.M{"name": "小亮"}
   update := bson.M{"$set": bson.M{"skill": "整个活!"}}
   updateResult, err := collection.UpdateOne(ctx, filter, update, updateOptions)
   if err != nil {
      log.Fatal(err)
   }
   fmt.Printf("matched: %v  modified: %v  upserted: %v  upsertedID: %v\n",
      updateResult.MatchedCount,
      updateResult.ModifiedCount,
      updateResult.UpsertedCount,
      updateResult.UpsertedID)
   fmt.Println(updateResult)
}

UpdateMany

package main

import (
   "context"
   "db/nosql/mongodb/demo01/config"
   "fmt"
   "log"
   "time"

   "go.mongodb.org/mongo-driver/bson"
   "go.mongodb.org/mongo-driver/mongo"
)

func main() {
   // ctx
   ctx, cancelFunc := context.WithTimeout(context.Background(), time.Second*10)
   defer cancelFunc()

   // client
   client, err := mongo.Connect(context.TODO(), config.ClientOpts)
   if err != nil {
      log.Fatal(err)
   }
   defer func() {
      if err = client.Disconnect(ctx); err != nil {
         panic(err)
      }
   }()

   collection := client.Database("test").Collection("person")
   // UpdateMany
   filter := bson.M{"level": 0}
   update := bson.M{"$set": bson.M{"level": 10}}
   updateResult, err := collection.UpdateMany(ctx, filter, update)
   if err != nil {
      log.Fatal(err)
   }
   fmt.Printf("matched: %v  modified: %v  upserted: %v  upsertedID: %v\n",
      updateResult.MatchedCount,
      updateResult.ModifiedCount,
      updateResult.UpsertedCount,
      updateResult.UpsertedID)
   fmt.Println(updateResult)
}

ReplaceOne

就影响数据层面和FindOneAndReplace没有差别。

package main

import (
   "context"
   "db/nosql/mongodb/demo01/config"
   "fmt"
   "log"
   "time"

   "go.mongodb.org/mongo-driver/bson"
   "go.mongodb.org/mongo-driver/mongo"
   "go.mongodb.org/mongo-driver/mongo/options"
)

func main() {
   // ctx
   ctx, cancelFunc := context.WithTimeout(context.Background(), time.Second*10)
   defer cancelFunc()

   // client
   client, err := mongo.Connect(context.TODO(), config.ClientOpts)
   if err != nil {
      log.Fatal(err)
   }
   defer func() {
      if err = client.Disconnect(ctx); err != nil {
         panic(err)
      }
   }()

   collection := client.Database("test").Collection("person")
   // FindOneAndReplace
   replaceOptions := options.Replace().SetUpsert(true)
   filter := bson.M{"name": "二次元刀哥"}
   replacement := bson.M{
      "name":   "二次元",
      "gender": "女",
      "level":  0,
      "msg":    "生日快乐",
   }
   updateResult, err := collection.ReplaceOne(ctx, filter, replacement, replaceOptions)
   if err != nil {
      log.Fatal(err)
   }
   fmt.Printf("matched: %v  modified: %v  upserted: %v  upsertedID: %v\n",
      updateResult.MatchedCount,
      updateResult.ModifiedCount,
      updateResult.UpsertedCount,
      updateResult.UpsertedID)
   fmt.Println(updateResult)
}

Delete

DeleteOne

 package main
 ​
 import (
    "context"
    "db/nosql/mongodb/demo01/config"
    "fmt"
    "log"
    "time"
 ​
    "go.mongodb.org/mongo-driver/bson"
    "go.mongodb.org/mongo-driver/mongo"
    "go.mongodb.org/mongo-driver/mongo/options"
 )
 ​
 func main() {
    // ctx
    ctx, cancelFunc := context.WithTimeout(context.Background(), time.Second*10)
    defer cancelFunc()
 ​
    // client
    client, err := mongo.Connect(context.TODO(), config.ClientOpts)
    if err != nil {
       log.Fatal(err)
    }
    defer func() {
       if err = client.Disconnect(ctx); err != nil {
          panic(err)
       }
    }()
 ​
    collection := client.Database("test").Collection("person")
    // DeleteOne
    deleteOptions := options.Delete().SetCollation(&options.Collation{
       CaseLevel: false, // 忽略大小写
    })
    filter := bson.M{"name": "虎哥"}
    deleteResult, err := collection.DeleteOne(ctx, filter, deleteOptions)
    if err != nil {
       log.Fatal(err)
    }
    fmt.Println("delete count:", deleteResult.DeletedCount)
    fmt.Println(deleteResult)
 }

DeleteMany

 package main
 ​
 import (
    "context"
    "db/nosql/mongodb/demo01/config"
    "fmt"
    "log"
    "time"
 ​
    "go.mongodb.org/mongo-driver/bson"
    "go.mongodb.org/mongo-driver/mongo"
    "go.mongodb.org/mongo-driver/mongo/options"
 )
 ​
 func main() {
    // ctx
    ctx, cancelFunc := context.WithTimeout(context.Background(), time.Second*10)
    defer cancelFunc()
 ​
    // client
    client, err := mongo.Connect(context.TODO(), config.ClientOpts)
    if err != nil {
       log.Fatal(err)
    }
    defer func() {
       if err = client.Disconnect(ctx); err != nil {
          panic(err)
       }
    }()
 ​
    collection := client.Database("test").Collection("person")
    // DeleteMany
    deleteOptions := options.Delete().SetCollation(&options.Collation{
       CaseLevel: false, // 忽略大小写
    })
    filter := bson.M{"level": 0}
    deleteResult, err := collection.DeleteMany(ctx, filter, deleteOptions)
    if err != nil {
       log.Fatal(err)
    }
    fmt.Println("delete count:", deleteResult.DeletedCount)
 }

批量操作BulkWrite

批量操作BulkWrite

事务transaction

事务transaction

Distinct和Count

Distinct

 package main
 ​
 import (
    "context"
    "db/nosql/mongodb/demo01/config"
    "fmt"
    "log"
    "time"
 ​
    "go.mongodb.org/mongo-driver/bson"
    "go.mongodb.org/mongo-driver/mongo"
    "go.mongodb.org/mongo-driver/mongo/options"
 )
 ​
 func main() {
    // ctx
    ctx, cancelFunc := context.WithTimeout(context.Background(), time.Second*10)
    defer cancelFunc()
 ​
    // client
    client, err := mongo.Connect(context.TODO(), config.ClientOpts)
    if err != nil {
       log.Fatal(err)
    }
    defer func() {
       if err = client.Disconnect(ctx); err != nil {
          panic(err)
       }
    }()
 ​
    //db := client.Database("test")         // 获取名为test的db
    //collection := db.Collection("person") // 获取collection
    collection := client.Database("test").Collection("person")
    // Distinct
    distinctOptions := options.Distinct().SetMaxTime(time.Second * 2)
    // 返回所有的level值(注意是不同的结果,重复的level值不会重复输出)
    fieldName := "level"
    filter := bson.M{}
    distinctValues, err := collection.Distinct(ctx, fieldName, filter, distinctOptions)
    for _, value := range distinctValues {
       fmt.Println(value)
    }
 }

Count

 package main
 ​
 import (
    "context"
    "db/nosql/mongodb/demo01/config"
    "fmt"
    "log"
    "time"
 ​
    "go.mongodb.org/mongo-driver/bson"
    "go.mongodb.org/mongo-driver/mongo"
 )
 ​
 func main() {
    // ctx
    ctx, cancelFunc := context.WithTimeout(context.Background(), time.Second*10)
    defer cancelFunc()
 ​
    // client
    client, err := mongo.Connect(context.TODO(), config.ClientOpts)
    if err != nil {
       log.Fatal(err)
    }
    defer func() {
       if err = client.Disconnect(ctx); err != nil {
          panic(err)
       }
    }()
 ​
    collection := client.Database("test").Collection("person")
    // Count
    // EstimatedDocumentCount
    totalCount, err := collection.EstimatedDocumentCount(ctx)
    if err != nil {
       log.Fatal(err)
    }
    fmt.Println(totalCount)
    // CountDocuments
    filter := bson.M{"gender": "男"}
    count, err := collection.CountDocuments(ctx, filter)
    if err != nil {
       log.Fatal(err)
    }
    fmt.Println(count)
 }

聚合Aggregate

聚合Aggregate

事件监控Watch

事件监控Watch

\