MongoDB

对MongoDB的初步学习。

MongoDB介绍

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
index index 索引
primary key 主键 MongoDB自动将_id字段设置为主键 primary key

MongoDB安装

通过docker安装比较方便。

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

首先docker pull拉取镜像:

1
docker pull mongo:5.0

接下来docker run启动容器:

1
2
3
4
5
6
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权限

MongoDB使用

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

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

数据库常用命令:

show dbs;:查看数据库

1
2
3
4
5
> show dbs;
admin 0.000GB
config 0.000GB
local 0.000GB
test 0.000GB

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

1
2
> use q1mi;
switched to db q1mi

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

1
2
> db;
q1mi

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

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

数据集常用命令:

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

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

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

1
2
> show collections;
student

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

1
2
> db.student.drop()
true

文档常用命令:

插入一条文档:

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

插入多条文档:

1
2
3
4
5
6
7
8
9
10
11
> db.student.insertMany([
... {name:"张三",age:20},
... {name:"李四",age:25}
... ]);
{
"acknowledged" : true,
"insertedIds" : [
ObjectId("5db14c4704b33457f8c0250a"),
ObjectId("5db14c4704b33457f8c0250b")
]
}

查询所有文档:

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

查询age>20岁的文档:

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

更新文档:

1
2
3
4
5
6
7
8
9
> 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 }

删除文档:

1
2
3
4
5
> 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操作MongoDB

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

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

客户端连接

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
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:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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举例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 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
}

然后主模块中引入配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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以逗号,分隔

    如:

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

    如:

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

获取db

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
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())
}

创建索引

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
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)
}

查看索引

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
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没有差别。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
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