mogodb是文档数据库,存储的是文档(Bson,json的二进制数据),内部执行引擎为JS解析器(谷歌v8),把文档储存成bson结构,在查询是转换为JS对象,可以通过熟悉的JS语法来操作。
mogodb和传统数据库区别:
传统数据库:结构化数据,设计了表结构后,每一行内容的列的类型是固定的。
mogodb文档数据库:表下的每篇文档都可以有自己独立的数据结构(json对象都可以有自己独特的属性和值)
1 安装mongodb
1.1 在主机安装和启动mongodb
(1) 安装mongodb
# 下载地址https://www.mongodb.org/dl/linux/x86_64
# 下载双数版本,例如3.6,而单数3.5是开发版本
#下载
wget http://downloads.mongodb.org/linux/mongodb-linux-x86_64-3.6.3.tgz?_ga=2.249742406.1729791217.1523023903-593615807.1523023903
#解压并安装到/usr/local目录下
tar xvf mongodb-linux-x86_64-3.6.3.tgz
mv mongodb-linux-x86_64-3.6.3 mongodb
mv mongodb /usr/local
# 把bin目录添加到环境变量
echo 'export PATH="$PATH:/usr/local/mongodb/bin"' >> /etc/bashrc
# 使当前终端生效
source /etc/bashrc
# 创建存放数据和日志文件夹
mkdir -p /data/mongodb/db
mkdir -p /data/mongodb/log
mongodb安装bin目录下程序说明:
- bsondump:导出bson结构
- mongo:客户端
- mongod:服务端
- mongodump:整体数据库导出(二进制)
- mongoexport:导出易识别的json文档或csv文档
- mongorestore:数据库整体导入
- mongos:路由器(分片时用)
- mongostat:观察状态
- mongotop:类似linux的top命令
(2) 启动mongodb
以参数方式启动
mongod --dbpath /data/mongodb/db --logpath /data/mongodb/log/mongodb.log --port 27017 --fork
# --dbpath:数据库储存目录,--logpath日志储存目录,--fork后台运行,--port运行端口
# 使用mongod --help查看有哪些参数:
# --dbpath 数据库路径(数据文件)
# --logpath 日志文件路径
# --master 指定为主机器
# --slave 指定为从机器
# --source 指定主机器的IP地址
# --pologSize 指定日志文件大小不超过64M.因为resync是非常操作量大且耗时,最好通过设置一个足够大的oplogSize来避免resync(默认的 oplog大小是空闲磁盘大小的5%)。
# --logappend 日志文件末尾添加,即使用追加的方式写日志
# --journal 启用日志
# --port 启用端口号
# --fork 在后台运行
# --only 指定只复制哪一个数据库
# --slavedelay 指从复制检测的时间间隔
# --auth 是否需要验证权限登录(用户名和密码)
# --syncdelay 数据写入硬盘的时间(秒),0是不等待,直接写入
# --notablescan 不允许表扫描
# --maxConns 最大的并发连接数,默认2000
# --pidfilepath 指定进程文件,不指定则不产生进程文件
# --bind_ip 绑定IP,绑定后只能绑定的IP访问服务
自定义mongodb配置文件方式启动
新建配置文件:
vim /usr/local/mongodb/mongodb.conf
填写下面内容如下:
fork=true # 允许程序在后台运行
#auth=true # 开启认证
logpath=/var/log/mongo/mongo.log
logappend=true # 写日志的模式:设置为true为追加。默认是覆盖
dbpath=/data/mongo/ # 数据存放目录
pidfilepath=/tmp/mongo/mongo.pid # 进程ID,没有指定则启动时候就没有PID文件。默认缺省。
port=27017
bind_ip=127.0.0.1 # 绑定地址。默认127.0.0.1,只能通过本地连接
# 设置为true,修改数据目录存储模式,每个数据库的文件存储在DBPATH指定目录的不同的文件夹中。
# 使用此选项,可以配置的MongoDB将数据存储在不同的磁盘设备上,以提高写入吞吐量或磁盘容量。默认为false。
# 建议一开始就配置次选项
directoryperdb=true
# 禁止日志
# 对应 journal 启用操作日志,以确保写入持久性和数据的一致性,会在dbpath目录下创建journal目录
nojournal=true
## max connections
# 最大连接数。默认值:取决于系统(即的ulimit和文件描述符)限制。
# MongoDB中不会限制其自身的连接。当设置大于系统的限制,则无效,以系统限制为准。
# 设置该值的高于连接池和总连接数的大小,以防止尖峰时候的连接。
# 注意:不能设置该值大于20000。
maxConns=1024
启动mongodb:
mongod -f /usr/local/mongodb/mongodb.conf
关闭mongodb服务:
mongod –shutdown –dbpath /data/mongodb/db
(3) 连接mongodb
mongodb客户端连接:
mongo –host 192.168.8.200 –port 27017
有密码连接:
mongo -u “vison” -p “123456” –host 192.168.8.200 –port 27017 –authenticationDatabase “crawler”
(3) 允许外网访问mongodb
如果使用命令行方式启动,则添加参数–bind_ip 0.0.0.0;如果使用配置文件方式启动,则修改配置文件字段为bind_ip=0.0.0.0。
(4) 查看mongodb连接数
netstat -nat | grep -i 27017 | wc -l
1.2 在docker安装mongodb
(1) 默认配置启动
docker run -d –name demo-mongo mongo:latest
docker run -d --name demo-mongo \
-e MONGO_INITDB_ROOT_USERNAME=root \
-e MONGO_INITDB_ROOT_PASSWORD=123456 \
mongo
(2) 自定义配置文件启动
docker run -d –name demo-mongo -p 27017:27017 -v /data/mongo:/etc/mongo mongo –config /etc/mongo/mongod.conf
mongod.conf配置文件内容如下:
fork=true # 允许程序在后台运行
#auth=true # 开启认证
logpath=/var/log/mongo/mongo.log
logappend=true # 写日志的模式:设置为true为追加。默认是覆盖
dbpath=/etc/mongo # 数据存放目录
pidfilepath=/tmp/mongo/mongodb.pid # 进程ID,没有指定则启动时候就没有PID文件。默认缺省。
port=27017
bind_ip=127.0.0.1 # 绑定地址。默认127.0.0.1,只能通过本地
directoryperdb=true
nojournal=true
maxConns=1024
(3) docker-compose命令启动,同时启动mongodb管理界面服务
version: '3.1'
services:
mongo:
image: mongo
restart: always
environment:
MONGO_INITDB_ROOT_USERNAME: root
MONGO_INITDB_ROOT_PASSWORD: 123456
ports:
- 27017:27017
volumes:
- /data/mongo:/etc/mongo
mongo-express:
image: mongo-express
restart: always
ports:
- 8081:8081
environment:
ME_CONFIG_MONGODB_ADMINUSERNAME: root
ME_CONFIG_MONGODB_ADMINPASSWORD: 123456
2 mongo账号管理
在mongodb中有一个admin数据库,牵涉到服务器配置层面的操作,需要先切换到admin数据库,use admin命令相当于进入超级用户管理模式。
mongo的用户是以数据库为单位来建立的,每个数据库有自己的管理员。
我们在设置用户时,需要先在admin数据库下建立管理员,这个管理员登陆后,相当于超级管理员,然后可以切换到其他库,添加普通用户。
注意: mongodb服务器启动时,默认不是需要认证的,要让用户生效,需要启动服务器时指定–auth选项。添加用户后,我们再次退出并登陆,认证才有效。
2.1 创建管理员
# (1)创建用户管理员(在管理身份验证数据库)。
use admin
db.createUser(
{
user: "admin",
pwd: "xxx",
roles: [{role: "userAdminAnyDatabase", db: "admin"}]
}
)
# (2)重新启动MongoDB实例与访问控制。
mongod --dbpath /data/mongodb/database --logpath /data/mongodb/log/mongodb.log --port 27017 --fork --auth
# (3)连接和用户管理员进行身份验证。
mongo --port 27017 -u "vison" -p "xxx" --authenticationDatabase "admin"
2.2 创建自定义用户
# (1) 给其他数据库test配置一个读写权限的用户
use test
db.createUser(
{
user: "myTester",
pwd: "xyz123",
roles: [ { role: "readWrite", db: "test" },
{ role: "read", db: "reporting" } ]
}
)
# (2)mytest连接和验证。
mongo --port 27017 -u "myTester" -p "xyz123" --authenticationDatabase "test"
# 或登录后执行命令验证
use test
db.auth("myTester","xyz123")
2.3 查看已经创建的用户
# 查看创建的用户需要在管理员数据库上执行
use admin
db.system.users.find()
# 查看当前数据库用户
show users
2.4 删除用户
# 删除一个用户
use dbname
db.system.users.remove({user:"username"})
# 删除管理员
use admin
db.system.users.remove({user:"admin"})
3 mongodb增删改查操作
3.1 库和集合的基础命令
(1) 库级命令
# 查看所有数据库
show dbs # 或使用mysql命令show databases;
# 切换到指定数据库
use 库名
# 创建数据库(mongodb不提供命令)
# mongodb的数据库是隐式创建的(创建表时自动创建),就算没有指定的库,也可以使用use命令。
# 删除数据库
db.dropDatabase()
(2) 表(集合)级命令
# 显示所有表
show collections; # 或mysql命令show tables;
# 创建表
db.createCollection('user')
# 删除表
db.user.drop()
3.2 insert 插入数据
(1) 增加一个文档
# 不指定id
db.user.insert({name:'张三',age:22})
# 指定id
db.user.insert({_id:10001,name:'李四',age:23})
(2) 一次增加多个文档
db.user.insert([{name:'张三',age:24},{_id:10002,name:'李四',age:25},{name:'王五',age:26}])
3.3 remove 删除数据
语法: > db.collection.remove(查询表达式,选项)
查询表达式: 类似mysql的where条件,不加条件会删除表所有数据。 选项: 是否删除一行,{justOne:true/false},默认是false
# 示例
db.user.remove({_id:10001})
db.user.remove({age:24},{ justOne:true})
注:实际应用中一般不使用删除,使用一个字段来标记删除。
3.4 update 修改数据
语法:
db.collection.updae(查询表达式,新值,选项)
错误示例:
db.user.update({name:‘张三’},{age:33})
注意:这种方式是新文档直接替换了旧文档,必须指定赋值表达式,常用表达式有:
表达式 | 说明 |
---|---|
$set | 设置字段新的值 |
$unset | 删除指定的列 |
$inc | 增长 |
$rename | 重命名该列 |
$setOnInsert | 当upsert时,设置字段的值 |
(1) 赋值表达式
# $set设置字段新值(如果字段不存在则新增加该列)
db.user.update({name:'张三'},{$set:{age:33}})
# $inc自增字段值
db.user.update({name:'张三'},{$inc:{age:1}})
# $rename修改字段名
db.user.update({name:'张三'},{$rename:{sex:'gender'}})
# $unset删除指定列
db.user.update({name:'张三'},{$unset:{phone:1}})
# setOnInsert当upsert为true时,添加附加字段
db.user.update({name:'赵六'},{$setOnInsert:{age:25,gender:'male'}},{upsert:true})
# 多种赋值表达可以一次执行
db.collection.updae(查询表达式,{
{$set:{...}},
{$unset:{...}},
{$inc:{...}},
{$rename:{...}}
})
(2) 修改选项
选项包括upsert和multi
- upsert:没有匹配的行,是否直接插入该行,默认为false。
- multi:查询表达式匹配中多行,是否修改多行,默认false(只修改一行)
# 示例
db.user.update({name:'李四'},{$set:{age:44}},{upsert:true})
db.user.update({gender:'male'},{$set:{age:55}},{multi:true})
3.5 query 查询
# 语法:db.collection.find(查询表达式,查询的列)
db.user.find() # 查询所有
# 查询匹配条件的所有列
db.user.find({name:'张三'})
# 查询匹配条件的指定列({列名:1,列名:1,...})
db.user.find({name:'张三'},{age:1})
# 不查询id列
db.user.find({name:'张三'},{_id:0,age:1})
(1) 字段值查询
# 查询主键为32的商品
db.goods.find({goods_id:32})
# 子文档查询(指向子文档的key是字符串)
db.stu.find({'score.yuwen':75})
# 数组元素查询(指向子文档的key是字符串)
db.stu.find({'hobby.2':'football'})
(2) 范围查询
# $ne 不等于
# 查询不属第3栏目的所有商品
db.goods.find({cat_id:{$ne:3}})
# $gt 大于
# 查询高于3000元的商品
db.goods.find({shop_price:{$gt:3000}})
# $gte 大于等于
# 查询高于或等于3000元的商品
db.goods.find({shop_price:{$gte: 3000}})
# $lt 小于
# 查询低于500元的商品
db.goods.find({shop_price:{$lt:500}})
# $lt 小于等于
# 查询低于500元的商品
db.goods.find({shop_price:{$lte:500}})
(3) 集合查询
# $in 在集合,(当查询字段是数组时,不需完全匹配也会命中该行)
# 查询栏目为4和11的商品
db.goods.find({cat_id:{$in:[4,11]}})
# $nin 不在集合
# 查询栏目不是3和4的商品
db.goods.find({cat_id:{$nin:[3,4]}})
# $all完全匹配,(当查询字段是数组时,必须完全匹配才命中该行)
db.goods.find({cat_id:{$all:[4,11]}})
(4) 逻辑查询
# $and 逻辑与,必须都满足条件
# 查询价格为100到500的商品
db.goods.find({$and:[{shop_price:{$gt:100}},{shop_price:{$lt:500}}]})
# $or 逻辑或,至少满足一个条件
# 查询价格小于100或大于3000的商品
db.goods.find({$or:[{shop_price:{$lt:100}},{shop_price:{$gt:3000}}]})
# $nor 与非逻辑
# 查询不在栏目3,并且价格不小1000的商品
db.goods.find({$nor:[{cat_id:3},{shop_price:{$lt:1000}}]})
(5) 元素运算符查询
# $mod 求余
# 查询年龄对10求余为0的用户
db.goods.find({age:{$mod:[10,0]}})
# $exist 查询列是否存在
# 查询有电话属性的用户
db.user.find({phone:{$exists:1}})
# $type 查询属性为指定类型的文档
# 查询为浮点型的文档
db.user.find({phone:{$type:1}})
# 查询为字符串型的文档
db.user.find({phone:{$type:2}})
(6) 其他常用查询
# 统计行数
db.goods.count()
db.goods.find({cat_id:3}).count()
# 查询每页数据
# 按指定属性排序,1表示升序,-1表示降序
sort({属性:1|-1})
# 跳过行数
skip(num)
# 限制取多少行
limit(num)
# 页码page,每页行数n,则skip数=(page-1)*n
db.goods.find({cat_id:3}).sort({shop_price:-1}).skip(0).limit(10)
4 索引
索引提高查询速度,降低写入速度,权衡常用的查询字段,不建议在太多列上建索引。在mongodb中,索引可以按字段升序/降序来创建,便于排序。默认是用btree来组织索引文件,也允许建立hash索引。
# 在test库下stu下创建10000行数据的成绩表
for (var i=1;i<=10000;i++){db.stu.insert({sn:i,name:'stu'+i,email:'stu'+i+'@126.com',score:{yuwen:i%80,shuxue:i%90,yingyu:i%100}})}
4.1 普通索引
(1) 单列索引
在表stu创建sn列索引
db.stu.ensureIndex({sn:1})
1表示升序,-1表示降序
(2) 多列索引
在表stu创建sn列和name列共同索引
db.stu.ensureIndex({sn:1,name:1})
1表示升序,-1表示降序
(3) 子文档索引
在表stu的score列下的yuwen字段创建索引
db.stu.ensureIndex({‘score.yuwen’:1})
1表示升序,-1表示降序
4.2 唯一索引
创建唯一索引后字段值都是唯一的
在表stu创建email列索引
db.stu.ensureIndex({email:1},{unique:true})
4.3 稀疏索引
稀疏索引的特点:如果针对field做索引,针对不含field列的文档,将不建立索引。与之相对的普通索引会把该文档的field列的值认为NULL,并建索引。
使用场景:小部分文档含有某列时。
在表stu创建phone列稀疏索引
db.stu.ensureIndex({age:1},{sparse:true})
4.4 哈希索引
哈希索引速度比普通索引快,缺点是不能对范围查询进行优化。使用场景:随机性强的散列
在表stu创建email列哈希索引
db.stu.ensureIndex({email:‘hashed’})
4.5 重建索引
一个表经过很多次修改后,导致表的文件产生空洞,索引文件也如此。可以通过索引的重建,减少索引文件碎片,并提高索引的效率,类似mysql中的optimize table
在表stu重建索引
db.stu.reIndex()
4.6 删除索引
# 语法
db.collection.dropIndex({filed:1/-1});
# 示例
db.stu.dropIndex({sn:1})
db.stu.dropIndex ({email:'hashed'})
4.7 查看索引和执行计划
# 查看表索引
db.stu.getIndexes()
# 查看执行计划
db.stu.find({sn:5555}).explain() # 默认只输出queryPlanner
# 其中explain()参数有三个,分别是'queryPlanner'、'executionStats'、'allPlansExecution'
db.stu.find({sn:5555}).explain('executionStats')
# explain分析结果的几个重要字段,通过结果分析可以判断是否需要优化执行语句
executionStats属性下的字段:
- executionTimeMillis:查询耗时,单位(ms)
- totalDocsExamined:扫描文档数
- executionStages.stage:”COLLSCAN”表示全表扫描,”FETCH”表示索引扫描
- executionStages. executionTimeMillisEstimate:索引扫描耗时,单位(ms)
winningPlan.inputStage属性下的字段:
- indexName:索引名字
5 数据备份与恢复
5.1 mongoexport导出json/csv结构化数据
mongoexport命令导出的只有数据,不包括索引,mongoexport参数说明:
- -h:主机ip或域名 (默认localhost)
- --port:mongodb使用端口 (默认27107)
- -u:认证用户名 (当需要认证时用)
- -p:认证密码 (当需要认证时用)
- -d:指定导出的库名
- -c:指定导出的表名
- -f:指定导出的列名
- -q:查询条件,例如:’{sn:{“$lte”:100}}’
- -o:保存导出数据文件位置
- --csv:指定导出csv格式 (便于和传统数据库交换数据),默认导出的json格式
# 导出json数据
mongoexport -h 192.168.8.200 --port 27017 -u vison -p 123456 -d test -c stu -f sn,name,email -q '{sn:{"$lte":100}}' -o /home/vison/src/test.stu.json
# 导出csv数据
mongoexport -h 192.168.8.200 --port 27017 -u vison -p 123456 -d test -c stu -f sn,name,email -q '{sn:{"$lte":100}}' --csv -o /home/vison/src/test.stu.csv
5.2 mongoimport导入json/csv结构化数据
mongoimport命令导出的只有数据,不包括索引,mongoimport参数说明:
- -h:主机ip或域名 (默认localhost)
- --port:mongodb使用端口 (默认27107)
- -u:认证用户名 (当需要认证时用)
- -p:认证密码 (当需要认证时用)
- -d:指定导入的库名
- -c:指定导入的表名(不存在会自己创建)
- --type:csv/json(默认json)
- --headline:当导入csv文件时,需要跳过第一行列名
- --file:导入数据文件的位置
# 导入json数据
mongoimport -h 192.168.8.200 --port 27017 -u vison -p 123456 -d test -c stu_json --type json --file /home/vison/src/test.stu.json
# 导入csv数据
mongoimport -h 192.168.8.200 --port 27017 -u vison -p 123456 -d test -c stu_csv --type csv --headerline --file /home/vison/src/test.stu.csv
# 注:老版本需要指定-fields参数
5.3 mongodump导出二进制数据
mongodump导出数据是包括索引的,mongodump的参数说明:
- -h:主机ip或域名 (默认localhost)
- --port:mongodb使用端口 (默认27107)
- -u:认证用户名 (当需要认证时用)
- -p:认证密码 (当需要认证时用)
- -d:指定导出的库名
- -c:指定导出的表名 (可选)
- -q:查询条件(可选),例如:’{sn:{“$lte”:100}}’
- -o:保存导出数据文件位置(默认是导出到mongo下的dump目录)
- --gzip:导出并压缩
示例:
mongodump -h 192.168.8.200 --port 27017 -u vison -p 123456 -d test --gzip -o /home/vison/src/mongoDump
注:可以写脚本每天凌晨访问少的时候备份一次数据
5.4 mongorestore导入二进制数据
mongorestore导出数据是包括索引的,mongorestore的参数说明:
- -h:主机ip或域名 (默认localhost)
- --port:mongodb使用端口 (默认27107)
- -u:认证用户名 (当需要认证时用)
- -p:认证密码 (当需要认证时用)
- -d:指定导出的库名
- -c:指定导出的表名 (可选)
- --dir:保存导入数据文件位置
- --gzip:导出并压缩
示例:
mongorestore -h 192.168.8.200 --port 27017 -u vison -p 123456 -d test --gzip --dir /home/vison/src/mongoDump/test
获取mongodb状态信息
首先在admin下创建一个新能够获取mongodb状态权限的用户
use admin
db.createUser(
{
user: "stat",
pwd: "123456",
roles: [{role: "mongostatRole", db: "admin"}]
}
)
每隔2秒采集一次信息保存到文件stat.log
mongostat -u stat -p 123456 –authenticationDatabase admin -n 2 –json >> stat.log
每一条统计信息如下:
{
"localhost:27017":{
"arw":"1|0",
"command":"2|0",
"conn":"4",
"delete":"*0",
"dirty":"0.0%",
"flushes":"0",
"getmore":"0",
"insert":"*0",
"net_in":"18.9k",
"net_out":"79.0k",
"qrw":"0|0",
"query":"94",
"res":"49.0M",
"time":"14:41:32",
"update":"*0",
"used":"0.1%",
"vsize":"938M"
}
}
更多mongostat命令说明看官网 https://docs.mongodb.com/manual/reference/program/mongostat/
非正常关闭mongodb导致无法启动的解决方法
非正常关闭包括断电或强制关闭,造成文件mongod.lock锁住了,所以无法正常启动,解决方法:
(1) 删除mongod.lock文件,文件存放一般在数据库文件夹里
rm /data/mongodb/db/mongod.lock
(2) repair的模式启动
mongod -f /usr/local/mongodb/mongodb.conf –repair
(3) 启动mongodb
mongod -f /usr/local/mongodb/mongodb.conf
专题「数据库」的其它文章 »
- etcd基础与使用 (Nov 15, 2020)
- mysql基础和使用 (Feb 17, 2019)
- redis基础和使用 (Dec 27, 2018)
- 搭建高可用redis集群 (Sep 26, 2018)
- 搭建高可用mysql集群PXC (Sep 21, 2018)