如何使用golang操作mongo

mongo介绍

特性

  • 高性能
  • 丰富的查询语言
  • 高可用
  • 水平伸缩
  • 支持多种存储引擎

分片集群四个组件

  1. mongos

    数据库集群请求的入口,所有的请求都通过mongos进行协调,不需要在应用程序添加一个路由选择器,mongos自己就是一个请求分发中心,它负责把对应的数据请求请求转发到对应的shard服务器上。在生产环境通常有多mongos作为请求的入口,防止其中一个挂掉所有的mongodb请求都没有办法操作。

  2. config server

    配置服务器,存储所有数据库元信息(路由、分片)的配置。mongos本身没有物理存储分片服务器和数据路由信息,只是缓存在内存里,配置服务器则实际存储这些数据。mongos第一次启动或者关掉重启就会从 config server 加载配置信息,以后如果配置服务器信息变化会通知到所有的 mongos 更新自己的状态,这样 mongos 就能继续准确路由。在生产环境通常有多个 config server 配置服务器,因为它存储了分片路由的元数据,防止数据丢失!

  3. shard

    分片(sharding)是指将数据库拆分,将其分散在不同的机器上的过程。将数据分散到不同的机器上,不需要功能强大的服务器就可以存储更多的数据和处理更大的负载。基本思想就是将集合切成小块,这些块分散到若干片里,每个片只负责总数据的一部分,最后通过一个均衡器来对各个分片进行均衡(数据迁移)。

  4. replia set

    shard的备份,防止shard挂掉之后数据丢失。复制提供了数据的冗余备份,并在多个服务器上存储数据副本,提高了数据的可用性, 并可以保证数据的安全性。

问题总结

  1. 在admin库中创建用户报 Error: couldn't add user: Use of SCRAM-SHA-256 requires undigested passwords

    解决方法:
    使用如下脚本创建用户

    1
    2
    3
    4
    5
    6
    7
    8
    db.createUser(
    {
    user: "username",
    pwd: "password",
    roles: [{role:"root",db:"admin"}],
    mechanisms: ["SCRAM-SHA-1"]
    }
    );
  2. 启动mongo报错 WiredTiger.wt: handle-open: open: No such file or directory

    解决方法:删除掉dbPath目录, 然后重启mongo

  3. 如果获取超过101条记录,mongodb不会一次性全部load并返回给client,每次只返回batchsize条记录,遍历完之后再通过网络获取。

Official Go Driver

mongo-go-driver

代码示例

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
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
package main
import (
"context"
"fmt"
"github.com/mongodb/mongo-go-driver/bson"
"github.com/mongodb/mongo-go-driver/mongo"
"os"
"os/signal"
"time"
)
var MongoClient *mongo.Client
func main() {
// 终端信号通道
signalChan := make(chan os.Signal, 1)
signal.Notify(signalChan, os.Interrupt)
// 初始化mongo client
initMongoClient()
collection := MongoClient.Database("test").Collection("doublesouth_test")
//testCollectionInsertOne(collection)
testCollectionFind(collection)
for range signalChan {
fmt.Println("收到终端信号,准备断开mongo连接...")
if err := destroyMongoClient(); err != nil {
fmt.Println("断开mongo连接失败", err)
} else {
fmt.Println("已断开mongo连接")
}
break
}
}
func initMongoClient() {
client, err := mongo.NewClient("mongodb://username:password@localhost:20000")
if err != nil {
panic(err)
}
ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second)
defer cancel()
err = client.Connect(ctx)
if err != nil {
panic(err)
}
MongoClient = client
}
func destroyMongoClient() error {
return MongoClient.Disconnect(context.Background())
}
func testCollectionInsertOne(collection *mongo.Collection) {
res, err := collection.InsertOne(context.Background(),
bson.M{
"name": "大虾3",
"age": int32(18),
"sex": "女",
"hobby": []string{"玩游戏", "看电影"},
})
if err != nil {
fmt.Println(err)
return
}
fmt.Println("_id:", res.InsertedID)
}
func testCollectionFind(collection *mongo.Collection) {
ctx := context.Background()
fmt.Println("findall-------------------------------------------")
cur, err := collection.Find(ctx, nil)
defer cur.Close(ctx)
if err != nil {
fmt.Println(err)
return
}
for cur.Next(ctx) {
raw, err := cur.DecodeBytes()
if err != nil {
fmt.Println(err)
return
}
fmt.Println(raw.String())
}
fmt.Println("findone-------------------------------------")
result := bson.Raw{}
filter := bson.D{{"name", "大虾3"}}
err = collection.FindOne(context.Background(), filter).Decode(&result)
if err != nil {
fmt.Println(err)
}
fmt.Println(result.String())
res := struct {
Name string
Age int32
Sex string
Hobby []string
}{}
err = collection.FindOne(context.Background(), filter).Decode(&res)
if err != nil {
fmt.Println(err)
}
fmt.Println(res)
}

参考链接

Mac mongo 可视化客户端 Robo 3T
MongoDB官方文档
Mongodb 与 MySQL性能对比
mongodb副本集加分片集群安全认证使用账号密码登录
mongodb 3.4 集群搭建:分片+副本集
MongoDB认证和授权详解
MongoDB 分片集群技术
Mongodb 教程
What is the difference between readPreference and readConcern in MongoDB?
mongodb 3.4与 mongodb 3.2性能对比

小伙伴,如果您觉得文章还不错,欢迎您的支持,我会继续努力创作!