MongoDB学习笔记

非关系型数据库

sql关系型数据库:MySQLPgSQL:一致性保证,支持事务

no-sql非关系型数据库:RedisMongoDBElasticSearch,事务能力不强

MongoDB:可记录json文档,丰富的查询能力,serveless宠儿

安装

学习使用,在k8s上安装单机版即可。集群版本待补充。

yaml文件:使用本地存储,有状态的方式部署,通过configmap注入配置。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# cat configMap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: mongodb-conf
data:
mongodb.conf: |
dbpath=/data/middleware-data/mongodb
logpath=/data/middleware-data/mongodb/mongodb.log
pidfilepath=/data/middleware-data/mongodb/master.pid
directoryperdb=true
logappend=true
bind_ip=0.0.0.0
port=27017
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#  cat Service.yaml
kind: Service
apiVersion: v1
metadata:
labels:
name: mongodb
name: mongodb
spec:
type: NodePort
ports:
- name: mongodb
port: 27017
targetPort: 27017
nodePort: 30002
selector:
name: mongodb
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
# cat StatefulSet.yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: mongodb
spec:
replicas: 1
serviceName: mongodb
selector:
matchLabels:
name: mongodb
template:
metadata:
labels:
name: mongodb
spec:
containers:
- name: mongodb
image: mongo:4.2.1
command:
- sh
- -c
- "exec mongod -f /data/middleware-data/mongodb/conf/mongodb.conf"
imagePullPolicy: IfNotPresent
ports:
- containerPort: 27017
name: mongodb
protocol: TCP
volumeMounts:
- name: mongodb-config
mountPath: /data/middleware-data/mongodb/conf/
- name: data
mountPath: /data/middleware-data/mongodb/
volumes:
- name: mongodb-config
configMap:
name: mongodb-conf
- name: data
hostPath:
path: /data/middleware-data/mongodb/
1
2
3
kubectl create -f configMap.yaml
kubectl create -f Service.yaml
kubectl create -f StatefulSet.yaml

简单学习增删改查,更加详细的操作和功能可查看官方文档:MongoDB中文手册|官方文档中文版

CRUD

创建数据库,如果数据库存在,则使用该数据库

1
use('userinfo');

创建集合(表),插入数据的时候会自动创建集合

增加一个数据

1
2
3
db.bookinfo.insertOne(
{open_id:"1"}
)

增加多个数据

1
2
3
4
5
6
7
8
9
db.bookinfo.insertMany([{
open_id:"1",
_id:"5",
login_count: 0,
},{
open_id:"2",
_id:"6",
login_count: 2,
}])

如果没有_id字段,会被自动分配一个字段

1
2
3
4
5
6
7
8
9
10
11
12
13
db.study1.insertOne({
a: 1
})

{
"_id": {"$oid": "62c659ecc15c1f1f67acce55"},
"a": 1
}

系统分配的_id可以通过ObjectId搜索
db.study1.find({
_id : ObjectId("62c659ecc15c1f1f67acce55")
})

删除集合

1
db.bookinfo.drop()

查询,返回数组

1
2
3
4
5
db.bookinfo.find()    // 	查询所有
db.bookinfo.find({ // 按条件查找
login_count : 0,
})

删除数据

1
2
3
db.bookinfo.deleteOne({
_id: "2"
})

更新,查找更新,非原子性

1
2
3
4
5
6
7
db.bookinfo.updateOne({
_id: "4"
},{
$set: {
login_count : 5
}
})

原子操作加1

1
2
3
4
5
6
7
db.bookinfo.updateOne({
_id: "4"
},{
$inc: {
login_count : 1
}
})

查询支持条件判断和嵌套结构体查找

创建索引

1
2
3
db.bookinfo.createIndex({
"login_count": 1 // login_count 从小到大创建索引,升序
})

Golang 操作MongoDB

官方文档:MongoDB Go Driver

import

1
2
3
go get go.mongodb.org/mongo-driver/mongo
go get go.mongodb.org/mongo-driver/mongo/options
go get go.mongodb.org/mongo-driver/mongo/readpref

连接

1
2
3
c := context.Background()
client, err := mongo.Connect(c, options.Client().ApplyURI(
"mongodb://192.168.41.249:30002/userinfo?readPreperence=primary&ssl=false"))

设置操作的databasecollection

1
col := client.Database("userinfo").Collection("userinfo")

增加

1
2
3
one, err := col.InsertOne(c, bson.M{
"user_id": "1001",
})

返回ObjectID

1
fmt.Printf("one: %+v\n", one.InsertedID) // ObjectID("62c6e84d601444ae1c1d3c5e")

批量增加

1
2
3
4
5
6
7
8
9
result, err := col.InsertMany(c, []interface{}{
bson.M{
"user_id": "1002",
},
bson.M{
"user_id": "1003",
},
})
fmt.Printf("%+v\n", result.InsertedIDs) // [ObjectID("62c6e84d601444ae1c1d3c5f") ObjectID("62c6e84d601444ae1c1d3c60")]

查询

查询一个

1
2
3
4
5
6
7
8
9
find := col.FindOne(c, bson.M{
"user_id": "1002",
})
u := struct {
ID primitive.ObjectID `bson:"_id"`
UserID string `bson:"user_id"`
}{}
find.Decode(&u)
fmt.Printf("u: %+v\n", u) {ID:ObjectID("62c6e84d601444ae1c1d3c5f") UserID:1002}

查询多个

1
2
3
4
5
6
7
var us []UserInfo
if err = cur.All(c, &us); err != nil {
panic(err)
}
for _, user := range us {
fmt.Println("user: ", user) // {ObjectID("62c6eb95a769d52ef97a53b4") 1001}
}

删除

1
2
3
4
5
//    delRes, _ := col.DeleteOne(c, bson.M{ // 删除一个
delRes, _ := col.DeleteMany(c, bson.M{ // 删除多个
"user_id": "1001",
})
fmt.Printf("delete res: %+v", delRes) // {DeletedCount:1}

更新

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// updateOne, _ := col.UpdateOne(c, bson.M{ // 更新一个
updateMany, _ := col.UpdateMany(c, bson.M{ // 批量更新
"user_id": "1002",
}, bson.M{
"$set": bson.M{
"name": "mitaka",
},
})

// 判断是否有更新
if updateMany.MatchedCount != 0 {
fmt.Println("matched and replaced an existing document")
return
}

常用场景

验证用户是否已经注册,如果注册,则返回这个用户的ObjectID,如果没有注册,则创建用户,并且返回ObjectID

1
2
3
4
5
6
7
8
9
10
11
opts := options.FindOneAndUpdateOptions{}
opts.SetUpsert(true)
opts.SetReturnDocument(options.After)
filter := bson.M{"user_id": "1013"}
update := bson.M{"$set": filter}
result := col.FindOneAndUpdate(c, filter, update, &opts)
res := struct {
ID primitive.ObjectID `bson:"_id"`
}{}
result.Decode(&res)
fmt.Printf("res %+v", res)