Tech:MongoDB(基本素养)

作为 <专家之路> 的开篇,写一写文档型数据库代表 MongoDB。只讲安装和基本的增删改查,不涉及分片,索引,复制,出错处理,聚合等。评级: 3系。

其实我不太乐意讲这些基本操作,网上都有,但是为了体现系统性,姑且还是来一波吧

(网上的可能有错,下面都是我又实际在自己电脑上跑过的)

评级: 初级(3系)
环境: docker, 单机 (后续会讲分片等会涉及模拟多机器,并发等)


安装配置

反正也就是个单机版本,用 docker 吧,简单

首先确保自己安装有 docker 环境,包括 docker-compose。

1
2
# 如果下载的 docker 没有包含 docker-compose 的话
sudo pip install docker-compose

mac 版本的 docker 自己去官网下载。

然后 mongo Db 和 客户端 mongo_express,我已经为你配置好了:

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
version: '3.1'

services:

mongo:
image: mongo
container_name: mongodb
restart: always
ports:
- 27117:27017
environment:
MONGO_INITDB_ROOT_USERNAME: 'admin'
MONGO_INITDB_ROOT_PASSWORD: 'adminx2'

mongo-express:
image: mongo-express
container_name: mongo_express
restart: always
ports:
- 6081:8081
environment:
ME_CONFIG_MONGODB_ENABLE_ADMIN: 'true'
ME_CONFIG_MONGODB_PORT: 27017
ME_CONFIG_BASICAUTH_USERNAME: 'owen' ## for web login
ME_CONFIG_BASICAUTH_PASSWORD: 'owenx2'
ME_CONFIG_MONGODB_ADMINUSERNAME: admin
ME_CONFIG_MONGODB_ADMINPASSWORD: 'adminx2'
#ME_CONFIG_SITE_SSL_ENABLED: 'false'
#ME_CONFIG_SITE_SSL_CRT_PATH: '' # certificate file
#ME_CONFIG_SITE_SSL_KEY_PATH: '' # keyfile

其实跑在本地,还要啥密码?这里安全起见,mongodb 还是要一下密码,web 登陆也要用密码。

跑起来:

1
$ docker-compose up -d

12-20-54-115813.jpg

12-25-37-122501.jpg

一气呵成,然后就可以做基本操作了,但是这里操作,不太好。

Mongo Express 并不利于初学者,更适合单独操作,更适合拿来查看,这里最好还去单独安装一个客户端。

(可以是使用命令行工具,不过不太方便,我个人使用的是 navicat,整体还不错)

12-38-45-123822.jpg

(单机版的,纯粹用于练习和实验,这里就不配置了)

因为配置需要要求你了解整个 MongoDB 的生态,包括协议,软件组成,工作方式;而这里,仅仅针对一般开发人员

基本CRUD

最重要的是查询语句的写法

数据库相关

刚建立的数据库,除非有数据(包括索引之类的,否则不会显示),为了方便,下面自建立一个:

1
2
3
use mine;

db.test.insert({'name': 'bob'}); # 集合不存在自动创建

然后就可以看到了,下面直接列相关命令:

1
2
3
4
5
6
7
8
9
10
11
12
13
show dbs

use mine # 没有的话,自动创建

db.stats() # 查看数据库相关的属性

db.dropdatabase() # 删除数据库

db.createCollection(name, option) # 创建集合

db.getCollectionNames() # 查看集合名字, Array

show roles # 查看当前数据库角色及其权限

角色相关

一般用不到,因为多数人是没有权限的。

大致关系如下: dbOwner = readWrite + dbAdmin + userAdmin.

(另外还有一个只读角色 read;当然也还有其他角色,略)

1
2
3
# 查看当前数据库的人员

show users

超级管理员: userAdminAnyDatabase,仅针对 admin 数据库

比如新增一个超级管理员:

1
2
3
4
5
6
7
8
9
use admin;

db.createUser(
{
user: "test1",
pwd: "test11",
roles: [ { role: "userAdminAnyDatabase", db: "admin" } ]
}
);

如果没有指定,则默认在当前数据库增加超级管理员。(实际认证而言,系统由不从你的数据库查看超级管理员权限,所以无效)

可以为某个数据库指定权限:

1
2
3
4
5
6
7
8
db.createUser(
  {
    user: "test2",
    pwd: "test2",
    roles: [ { role: "readWrite", db: "mine" },
             { role: "userAdmin", db: "mine" } ]
  }
)

插入相关

有几类?

  • 单条记录插入
  • 多条记录插入 (json 数组;事务特性)
  • 是否有序插入 ({ordered:true},默认出错则一条都不插入)
  • 自己指定记录的 "_id"
  • 自己指定写出错机制 {writeConcern: {w: 'majority', wtimeout: 5000}}

以及简化命令 insertOne()insertMany()

举个例子吧:

1
2
3
4
5
6
7
8
9
10
db.test1.insertMany([
{name: 'xxx'},
{name: 'yyy'}
], {
ordered: true,
writeConcern: {w: 'majority', wtimeout: 5000}
}
);

db.test1.find();

建议: 尽量使用新的API,比如 insertOne

查询相关

一般格式就是 db.集合名.find(查询条件, 投影字段)。 (都需要以文档的形式指定,即 {})

普通查询:

1
2
3
4
5
6
# 查询上面注入的数据,_id 字段就不要显示了

db.test1.find(
{name: 'xxx'},
{_id:0}
)

不特别在 projection 部分标明的,都需要显示。这里 _id:0 指定了不显示,所以不会显示 _id 字段。
(条件指定为空 {} 表示全匹配,相当于不指定条件)

条件中的嵌套怎么办?

嵌套,即.查询,因为本质上指定的查询部分就是一个 json 文档:

1
2
3
4
5
6
7
8
9
10
11
use mine;

db.test1.insert(
{
name: {
full: 'xxxx',
alias: 'xxx'
}
}
);
db.test1.find({'name.alias': 'xxx'});

14-11-56-141133.jpg

数组查询: 条件里面可以当做数组,也可以当做普通字段

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
use mine;

db.test1.insertOne(
{
name: "zzz",
"tags": ["good", "cool", "great", "perfect"]
}
);


# 查询1
db.test1.find({"tags": ["good", "cool", "great", "perfect"]})

# 查询2: 当做普通查询,不写 [] ,数组里存在某个值就满足条件啦
db.test1.find({"tags": "cool"})

# 查询3: 按元素个数
db.test1.find({"tags": {$size:4}})

操作符查询: 和SQL并无区别 (只是用于文档而已)

比如 $in:

1
2
3
4
5
6
# 数组的元素是 good 或者 great
db.test1.find({"tags": {$in:["good", "great" ] }});

db.test1.find({"tags": {$in:["xx", "great" ] }}); # 依旧能查询到

db.test1.find({"tags": {$in:["xx", "yyy" ] }}); # 查询结果为空

{操作符: <value>},一般用到的有:

  • $lt, $lte
  • $gt, $gte
  • $ne
  • {key1:value1, key2, value2} 这里逗号就是 and 查询
  • $or,这里用数组符号 {$or: [{key1:value1, key2, value2}]}
  • $regex,一般写成 {$regex: /pattern/<option>},option 部分可以不写
    • 默认贪婪匹配,区分大小写

正则查询: 上面的 $regex 几乎等价于 SQL 中的 like

多表查询(聚合): 涉及聚合 aggregate 或者分组查询,多表查询。

略.(见后面的文章)(其实用字段.操作,就避免使用 join 这种不高效的做法)

补充:

find() 后面可以接 limit(数字)skip(数字)pretty()count(),前两者一看就是用于分页的呀。

删除相关

和 SQL 的 delete, drop, truncate 一样,这里也有多个选择。

这里 remove 只会删除集合数据,如果要把集合本身以及其所含索引全部删除,则应该使用 drop。

  • 删除表和删除数据的区别

全部删除:

1
db.test1.remove({})

指定条件删除

1
2
# 删除 id 为 1 的记录
db.test1.remve({"_id": 1});

默认会删除所有符合条件的元素,可以用 {“justOne”: true} 来指定只删除一条。

1
2
3
use mine;
db.test1.insert({price: 1});
db.test1.remove({price: {$gt:3}}, {justOne: true});

如果集合的文档数据中包含特定语言的数据,那么可能还要指定语言序列:

1
{callation: {local: "具体的location值", strength: 1}}

更新相关

其实很简单,根据查询条件找到记录,更新值。

  • 不存在,是否新增? upsert 选项
  • 是否只更新查询到的第一条,默认是的,即 multi 选项为 false

就这样语法:

1
2
3
4
5
6
7
8
9
10
db.collection.update(
<query>,
<update>,
{
upsert: <boolean>,
multi: <boolean>,
writeConcern: <document>,
collation: <>document>
}
)

<update> 部分的文档怎么写: {操作符: {字段名: 字段值}}
常用的操作符:

  • $set: 设置为某个值
    • $unset 删除某个字段, 例如 {$unset: {unit: "亿"}}
  • $inc: increase by cetain value
  • $mul: 乘法
  • $rename: 给查询到的字段改名
  • $max$min 最大最小值限定 (如果旧的值不再这个最大最小规定内,则修改为最大,最小指定的值)

时间可以使用 ISODate(),例如: ISODate("2019-08-09 12:00:00") 或者标准时间格式 ISODate("2013-10-02T01:11:18.965Z"),而不用 $set,也可以使用 {$currentDate: {字段名: true}:

1
2
3
4
5
6
7
8
9
10
11
# 插入当前时间
db.test2.insert({
ddate: ISODate()
});

# 用 $currentDate 更新时间 (因为就一条记录,就不指定条件了)
use mine;
db.test2.update(
{},
{$currentDate:{ ddate:{$type: "date"}}}
);

最常见的使用情况也如下:

1
2
3
4
5
6
# 常见1,不存在不要新插入,更新查找到的全部 (默认两者都是 false)
db.test3.update({"type":1}, {$set:{"name":"birdben"}}, false, true);


# 嫌弃 $set 麻烦,而想直接写具体的结果,那就用 replace命令吧
db.test3.replaceOne({"type":1}, {"name":"birdben"});

replaceOne 命令不允许出现任何操作符。

新纪录如果新增了字段的类型,那么一般会把 upsert 设置为 true。

建议: 多用 updateOne()updateMany()


MongoDB 没约束,没检查,多随意…

CH-YK 2019.06

文章目录
  1. 1. 安装配置
  2. 2. 基本CRUD
    1. 2.1. 数据库相关
    2. 2.2. 角色相关
    3. 2.3. 插入相关
    4. 2.4. 查询相关
    5. 2.5. 删除相关
    6. 2.6. 更新相关
|