before
mongoexport和mongoimport
先来看这两个命令的常用参数解释:
# 使用 --help 来查看 mongoexport 的用法
[mongod@cs ~]$ mongoexport --help
-h:主机名
-u:用户名
-p:密码
--authenticationDatabase:认证库
-d:要导出的库名
-c:要导出库下的集合
-f:要导出的字段
-o:导出数据的文件名
-q:导出数据时的过滤条件
--type:导出数据的格式,默认为json格式,可以通过 --type=csv 导出数据为csv格式
# 使用 --help 来查看 mongoexport 的用法
[mongod@cs ~]$ mongoimport --help
-h:主机名
-u:用户名
-p:密码
--authenticationDatabase:认证库
-d:要导入的库名
-c:要导入库下的集合
-f:要导入的字段
--type:导入数据的格式
--headerline:如果导入的文件是csv文件,并且有title行,使用title行作为字段
--file:导入文件的路径
导入导出json格式数据
导出json格式数据
准备数据:
[mongod@cs ~]$ mongo -uroot -p1234
> use t1
> for(i=1;i<=100;i++){db.s1.insert({"id":i,"name":"zhangkai","age":i,"date":new Date()})}
WriteResult({ "nInserted" : 1 })
> db.s1.find({id:1})
{ "_id" : ObjectId("60010ac816e872408ff3630c"), "id" : 1, "name" : "zhangkai", "age" : 1, "date" : ISODate("2021-01-15T03:23:52.645Z") }
> db.s1.count()
100
现在,我们将上面t1
库中的s1
表中的数据导出为json格式的数据,并保存到磁盘。
[mongod@cs ~]$ mongoexport -uroot -p1234 --port 27017 --authenticationDatabase admin -d t1 -c s1 -o /tmp/s1.json
2021-01-15T11:26:56.960+0800 connected to: localhost:27017
2021-01-15T11:26:56.963+0800 exported 100 records
[mongod@cs ~]$ wc -l /tmp/s1.json # wc -l 统计文件的行数
100 /tmp/s1.json
[mongod@cs ~]$ cat /tmp/s1.json | head -n 3 # 返回文件的前三行
{"_id":{"$oid":"60010ac816e872408ff3630c"},"id":1.0,"name":"zhangkai","age":1.0,"date":{"$date":"2021-01-15T03:23:52.645Z"}}
{"_id":{"$oid":"60010ac816e872408ff3630d"},"id":2.0,"name":"zhangkai","age":2.0,"date":{"$date":"2021-01-15T03:23:52.659Z"}}
{"_id":{"$oid":"60010ac816e872408ff3630e"},"id":3.0,"name":"zhangkai","age":3.0,"date":{"$date":"2021-01-15T03:23:52.660Z"}}
注意,MongoDB默认导出的是json格式的数据,并且一次只能将一个集合导出到一个文件。
导入json格式数据
[mongod@cs ~]$ mongoimport -uroot -p1234 --port 27017 --authenticationDatabase admin -d t1 -c s2 /tmp/s1.json
2021-01-15T11:36:32.867+0800 connected to: localhost:27017
2021-01-15T11:36:32.877+0800 imported 100 documents
[mongod@cs ~]$ mongo -uroot -p1234
> use t1
switched to db t1
> db.s2.count()
100
> db.s2.find({id:1})
{ "_id" : ObjectId("60010ac816e872408ff3630c"), "id" : 1, "name" : "zhangkai", "age" : 1, "date" : ISODate("2021-01-15T03:23:52.645Z") }
导入和导出json格式数据相对简单。
导入导出csv格式数据
还是使用上面的t1
库中的s1
集合作为演示。
导出csv格式数据
[mongod@cs ~]$ mongoexport -uroot -p1234 --port 27017 --authenticationDatabase admin -d t1 -c s1 --type=csv -f id,name,age,date -o /tmp/s1.csv
2021-01-15T11:47:47.934+0800 connected to: localhost:27017
2021-01-15T11:47:47.936+0800 exported 100 records
[mongod@cs ~]$ wc -l /tmp/s1.csv # 多出来的一行是title行
101 /tmp/s1.csv
[mongod@cs ~]$ cat /tmp/s1.csv | head -n 3
id,name,age,date
1,zhangkai,1,2021-01-15T03:23:52.645Z
2,zhangkai,2,2021-01-15T03:23:52.659Z
其中:
--type
表示导出的数据为csv格式。-f
表示要导出哪些字段,且这些字段会称为csv文件的title。
导入csv格式数据
[mongod@cs ~]$ mongoimport -uroot -p1234 --port 27017 --authenticationDatabase admin -d t1 -c s3 --type=csv --headerline --file /tmp/s1.csv
2021-01-15T11:53:50.540+0800 connected to: localhost:27017
2021-01-15T11:53:50.547+0800 imported 100 documents
[mongod@cs ~]$ mongo -uroot -p1234
> use t1
switched to db t1
> db.s3.count()
100
> db.s3.find({id:1})
{ "_id" : ObjectId("600111cedcfab91917ebdbab"), "id" : 1, "name" : "zhangkai", "age" : 1, "date" : "2021-01-15T03:23:52.645Z" }
其中:
--type
,因为源数据是csv数据,所以使用该参数进行声明。--headerline
,因为s1.csv
文件的首行是title,所以,使用这个参数声明使用文件中的title行作为字段。
注意,如果源数据csv文件没有title行,那么你导入的时候,就要手动指定了。
# 如果 csv 文件没有 title
18,zhangkai,18,2021-01-15T03:23:52.645Z
29,zhangkai,19,2021-01-15T03:23:52.645Z
# 导入时要通过 -f 参数指定字段,否则导入失败
mongoimport -uroot -p1234 --port 27017 --authenticationDatabase admin -d t1 -c s4 --type=csv -f id,name,age,date --file /tmp/s1.csv
除此之外,还有一种情况,需要我们注意,那就是集合中存储的文档是嵌套结构的,比如:
{
"_id" : ObjectId("6001157f93473d2a5f0938e7"),
"id" : 1,
"name" : "zhangkai",
"age" : 1,
"date" : ISODate("2021-01-15T04:09:35.238Z"),
"info" : {
"tel" : 13245546776,
"city" : "北京"
}
}
那这种嵌套结构的集合该如何导出?导出的结果又是什么样的?一起来看看:
[mongod@cs ~]$ mongo -uroot -p1234
> use t1
switched to db t1
> db.s5.insert({"id" : 1, "name" : "zhangkai", "age" : 1, "date" : new Date(), "info": {"tel":13245546776, "city": "北京"}})
WriteResult({ "nInserted" : 1 })
> exit
bye
[mongod@cs ~]$ mongoexport -uroot -p1234 --port 27017 --authenticationDatabase admin -d t1 -c s5 --type=csv -f id,name,age,date,info -o /tmp/s5.csv
2021-01-15T12:11:23.089+0800 connected to: localhost:27017
2021-01-15T12:11:23.089+0800 exported 1 record
[mongod@cs ~]$ cat /tmp/s5.csv
id,name,age,date,info
1,zhangkai,1,2021-01-15T04:09:35.238Z,"{""tel"":1.3245546776e+10,""city"":""北京""}"
可以看到,嵌套结构整体被当作为一个字符串了,但这种数据在导入到MongoDB中就不那么美丽了:
[mongod@cs ~]$ mongoimport -uroot -p1234 --port 27017 --authenticationDatabase admin -d t1 -c s6 --type=csv --headerline --file /tmp/s5.csv
2021-01-15T12:16:11.281+0800 connected to: localhost:27017
2021-01-15T12:16:11.290+0800 imported 1 document
[mongod@cs ~]$ mongo -uroot -p1234
> use t1
switched to db t1
> db.s6.find({id:1}).pretty()
{
"_id" : ObjectId("6001170bdcfab91917ebdc59"),
"id" : 1,
"name" : "zhangkai",
"age" : 1,
"date" : "2021-01-15T04:09:35.238Z",
"info" : "{\"tel\":1.3245546776e+10,\"city\":\"北京\"}"
}
由结果看到,嵌套结构并没有自动处理,而是原封不动的处理为字符串了。怎么解决?对于嵌套结构的数据,导出时选择json,避免这种文件,或者Python手动来处理和导入。
虽然csv文件固然有这样的缺点,但它也有点,那就是可以和关系型数据库打交道,实现异构平台数据迁移。
异构平台数据迁移
在实际开发中,通常会遇到将MySQL中的数据迁移到MongoDB中,所以,这里我们再来演示下,如何将MySQL数据迁移到MongoDB中。
首先,在MySQL中设置安全目录,使允许导入导出:
[root@cs tmp]# vim /etc/my.cnf
[mysqld]
secure-file-priv=/tmp
[root@cs tmp]# systemctl restart mysqld
然后准备数据,并将数据导出为csv文件。
-- 创建SQL文件
[root@cs tmp]# vim class.sql
DROP DATABASE IF EXISTS school;
CREATE DATABASE school CHARSET utf8;
USE school
SET AUTOCOMMIT=0;
SET NAMES utf8;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for `class`
-- ----------------------------
DROP TABLE IF EXISTS `class`;
CREATE TABLE `class` (
`cid` int(11) NOT NULL AUTO_INCREMENT,
`caption` varchar(32) NOT NULL,
PRIMARY KEY (`cid`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of `class`
-- ----------------------------
BEGIN;
INSERT INTO `class` VALUES ('1', '三年二班'), ('2', '三年三班'), ('3', '一年二班'), ('4', '二年九班');
COMMIT;
-- 将数据导入到MySQL中,此时会在 school 库中创建 class 表,并生成4条记录
[root@cs tmp]# mysql -uroot -p123 <class.sql
[root@cs tmp]# mysql -uroot -p123
3306 [(none)]>select * from school.class;
+-----+--------------+
| cid | caption |
+-----+--------------+
| 1 | 三年二班 |
| 2 | 三年三班 |
| 3 | 一年二班 |
| 4 | 二年九班 |
+-----+--------------+
4 rows in set (0.00 sec)
-- 这一步将 class 表中的数据导出到 /tmp/class.csv,并且字段之间以逗号分隔,默认是空格
3306 [(none)]>select * from school.class into outfile '/tmp/class.csv' fields terminated by ',';
Query OK, 4 rows affected (0.01 sec)
3306 [(none)]>exit
Bye
[root@cs tmp]# wc -l class.csv
4 class.csv
[root@cs tmp]# cat class.csv
1,三年二班
2,三年三班
3,一年二班
4,二年九班
由上述cat查看文件,发现csv文件并没有title行,所以,后续我们导入到MongoDB时,要注意这点。
现在,我们将csv文件导入到MongoDB:
[mongod@cs ~]$ mongoimport -uroot -p1234 --port 27017 --authenticationDatabase admin -d t1 -c s7 --type=csv -f cid,caption --file /tmp/class.csv
2021-01-15T15:06:35.270+0800 connected to: localhost:27017
2021-01-15T15:06:35.278+0800 imported 4 documents
[mongod@cs ~]$ mongo -uroot -p1234
MongoDB shell version v3.6.12
connecting to: mongodb://127.0.0.1:27017/?gssapiServiceName=mongodb
Implicit session: session { "id" : UUID("c40b96fc-6501-4cdc-98a7-76eaa9868692") }
MongoDB server version: 3.6.12
> use t1
switched to db t1
> db.s7.find()
{ "_id" : ObjectId("60013efbdcfab91917ebdc98"), "cid" : 1, "caption" : "三年二班" }
{ "_id" : ObjectId("60013efbdcfab91917ebdc99"), "cid" : 3, "caption" : "一年二班" }
{ "_id" : ObjectId("60013efbdcfab91917ebdc9a"), "cid" : 2, "caption" : "三年三班" }
{ "_id" : ObjectId("60013efbdcfab91917ebdc9b"), "cid" : 4, "caption" : "二年九班" }
可以看到,非常成功。
而一般很少有将MongoDB中的数据迁移到MySQL中,所以,这里不再多表。
mongodump和mongorestore
mongodump能够在MongoDB运行期间进行数据备份,它可以:
- 全备,对MongoDB中所有的数据进行备份。
- 备份指定库,单独对某个库的数据进行备份。
- 备份指定集合,单独对某个库下的某个集合进行备份。
- 压缩备份,可以在备份时,进行数据压缩。
mongodump工作原理就是对运行的MongoDB做查询,将查询结果写入磁盘,达到备份目的。但如果在备份时仍有写入操作,这些数据将不会被备份。所以,mongodump备份的数据完全和MongoDB的实时数据相等,并且在备份时会对性能有一定影响。建议在晚间进行备份,同时避开balancer的工作时间窗口。
mongodump的用法如下:
# 使用 --help 来查看 mongodump 的用法
[mongod@cs ~]$ mongodump --help
-h:主机名
-u:用户名
-p:密码
--authenticationDatabase:认证库
-d:指定库
-c:指定集合
-o:指定导出文件名
-q:导出数据的过滤条件
-j, --numParallelCollections:并发备份,默认值是4
--oplog:备份的同时备份oplog
--gzip:压缩备份
再来看mongorestore,它能:
- 从全备中恢复全部数据。
- 从全备中恢复指定库。
- 从全备中恢复指定库下指定集合。
mongorestore的用法如下:
# 使用 --help 来查看 mongorestore 的用法
[mongod@cs ~]$ mongorestore --help
-h:主机名
-u:用户名
-p:密码
--authenticationDatabase:认证库
-d:恢复到指定库
-c:恢复到指定集合
--drop:(谨慎使用)覆盖恢复
来看具体怎么用。
备份
准备一些目录用于存放被备份:
[mongod@cs ~]$ mkdir -p /data/mongodb_data/backup/{full,full_zip,t1,t1_zip,s1,s1_zip}
[mongod@cs ~]$ ll /data/mongodb_data/backup/
total 0
drwxrwxr-x. 2 mongod mongod 6 Jan 15 16:35 full # 存放全备数据
drwxrwxr-x. 2 mongod mongod 6 Jan 15 16:35 full_zip # 存放压缩全备数据
drwxrwxr-x. 2 mongod mongod 6 Jan 15 16:35 s1 # 存放s1集合的备份数据
drwxrwxr-x. 3 mongod mongod 6 Jan 15 16:35 s1_zip # 存放s1集合的压缩备份数据
drwxrwxr-x. 2 mongod mongod 6 Jan 15 16:35 t1 # 存放t1库的备份数据
drwxrwxr-x. 3 mongod mongod 6 Jan 15 16:35 t1_zip # 存放t1库的压缩备份数据
来看具体备份命令:
# 备份指定库,--gzip表示开启压缩备份
mongodump -uroot -p123 --port 27017 --authenticationDatabase admin -d t1 -o /data/mongodb_data/backup/t1
mongodump -uroot -p123 --port 27017 --authenticationDatabase admin -d t1 -o /data/mongodb_data/backup/t1 --gzip
# 备份指定库下指定集合,--gzip表示开启压缩备份
mongodump -uroot -p123 --port 27017 --authenticationDatabase admin -d t1 -c s1 -o /data/mongodb_data/backup/s1
mongodump -uroot -p123 --port 27017 --authenticationDatabase admin -d t1 -c s1 -o /data/mongodb_data/backup/s1 --gzip
全库备份
# 全库备份,--gzip表示开启压缩备份
mongodump -uroot -p123 --port 27017 --authenticationDatabase admin -o /data/mongodb_data/backup/full
mongodump -uroot -p123 --port 27017 --authenticationDatabase admin -o /data/mongodb_data/backup/full_zip --gzip
[mongod@cs ~]$ mongodump -uroot -p1234 --port 27017 --authenticationDatabase admin -o /data/mongodb_data/backup/full
[mongod@cs ~]$ ls /data/mongodb_data/backup/full
admin t1 t2 t3
[mongod@cs ~]$ ls /data/mongodb_data/backup/full/admin/
system.users.bson system.users.metadata.json system.version.bson system.version.metadata.json
[mongod@cs ~]$ ls /data/mongodb_data/backup/full/t1/
s1.bson s2.bson s3.bson s4.bson s5.bson s6.bson s7.bson
s1.metadata.json s2.metadata.json s3.metadata.json s4.metadata.json s5.metadata.json s6.metadata.json s7.metadata.json
由备份结果可以看到,mongodump备份了MongoDB实例中的:
- 系统库只备份
admin
库,因为该库存储了用户信息。 - 所有的应用库。
然后每个库备份到本地是个目录,其目录内存储了库中的各个集合,而每个集合会保存为两个:
collection.bson
,就是二进制的json文件。collection.metadata.json
是元数据,存储集合的字段信息。
再来看压缩备份有啥区别:
[mongod@cs ~]$ mongodump -uroot -p1234 --port 27017 --authenticationDatabase admin -o /data/mongodb_data/backup/full_zip --gzip
[mongod@cs ~]$ ls /data/mongodb_data/backup/full_zip/
admin t1 t2 t3
[mongod@cs ~]$ ls /data/mongodb_data/backup/full_zip/admin/
system.users.bson.gz system.users.metadata.json.gz system.version.bson.gz system.version.metadata.json.gz
[mongod@cs ~]$ ls /data/mongodb_data/backup/full_zip/t1/
s1.bson.gz s2.metadata.json.gz s4.bson.gz s5.metadata.json.gz s7.bson.gz
s1.metadata.json.gz s3.bson.gz s4.metadata.json.gz s6.bson.gz s7.metadata.json.gz
s2.bson.gz s3.metadata.json.gz s5.bson.gz s6.metadata.json.gz
区别就是,将原备份文件压缩了!
备份指定库
通过-d
参数来指定要备份的库:
# 备份指定库,--gzip表示开启压缩备份
mongodump -uroot -p1234 --port 27017 --authenticationDatabase admin -d t1 -o /data/mongodb_data/backup/t1
mongodump -uroot -p1234 --port 27017 --authenticationDatabase admin -d t1 -o /data/mongodb_data/backup/t1_zip --gzip
# 示例
[mongod@cs ~]$ mongodump -uroot -p1234 --port 27017 --authenticationDatabase admin -d t1 -o /data/mongodb_data/backup/t1
[mongod@cs ~]$ ls /data/mongodb_data/backup/t1
t1
[mongod@cs ~]$ ls /data/mongodb_data/backup/t1/t1/
s1.bson s2.bson s3.bson s4.bson s5.bson s6.bson s7.bson
s1.metadata.json s2.metadata.json s3.metadata.json s4.metadata.json s5.metadata.json s6.metadata.json s7.metadata.json
[mongod@cs ~]$ mongodump -uroot -p1234 --port 27017 --authenticationDatabase admin -d t1 -o /data/mongodb_data/backup/t1_zip --gzip
[mongod@cs ~]$ ls /data/mongodb_data/backup/t1_zip/
t1
[mongod@cs ~]$ ls /data/mongodb_data/backup/t1_zip/t1/
s1.bson.gz s2.metadata.json.gz s4.bson.gz s5.metadata.json.gz s7.bson.gz
s1.metadata.json.gz s3.bson.gz s4.metadata.json.gz s6.bson.gz s7.metadata.json.gz
s2.bson.gz s3.metadata.json.gz s5.bson.gz s6.metadata.json.gz
备份指定库也就是备份所有库中的其中一个库,但思路和全备一样。
备份指定集合
通过-d
指定备份的库,通过-c
指定备份该库下的指定集合:
# 备份指定库下指定集合,--gzip表示开启压缩备份
mongodump -uroot -p1234 --port 27017 --authenticationDatabase admin -d t1 -c s1 -o /data/mongodb_data/backup/s1
mongodump -uroot -p1234 --port 27017 --authenticationDatabase admin -d t1 -c s1 -o /data/mongodb_data/backup/s1_zip --gzip
# 示例
[mongod@cs ~]$ ls /data/mongodb_data/backup/s1
t1
[mongod@cs ~]$ ls /data/mongodb_data/backup/s1/t1/
s1.bson s1.metadata.json
[mongod@cs ~]$ ls /data/mongodb_data/backup/s1_zip/
t1
[mongod@cs ~]$ ls /data/mongodb_data/backup/s1_zip/t1/
s1.bson.gz s1.metadata.json.gz
备份指定集合,思路跟备份指定库一样,只不过只备份该库中的其中一个集合。
恢复
恢复全库备份
我这里准备了一个新的MongoDB实例,并监听28020端口,这里演示如何将上面的全备数据恢复到28020这个库中:
[mongod@cs ~]$ mongorestore -uroot -p1234 --port 28020 --authenticationDatabase admin /data/mongodb_data/backup/full
[mongod@cs ~]$ mongo -uroot -p1234 --port 28020
> show dbs;
admin 0.000GB
config 0.000GB
local 0.000GB
t1 0.000GB
t2 0.000GB
t3 0.000GB
> use t1
switched to db t1
> show tables;
s1
s2
s3
s4
s5
s6
s7
> db.s1.count()
100
由查询结果可以发现,我们完整了恢复了全备数据。
再来看,恢复带压缩的备份怎么恢复:
mongorestore -uroot -p1234 --port 28020 --authenticationDatabase admin /data/mongodb_data/backup/full_zip --gzip
2021-01-15T18:37:06.938+0800 no indexes to restore
2021-01-15T18:37:06.938+0800 finished restoring t1.s3 (100 documents)
2021-01-15T18:37:06.938+0800 restoring users from /data/mongodb_data/backup/full_zip/admin/system.users.bson.gz
2021-01-15T18:37:06.957+0800 done
因为之前已经恢复了全部数据,所以这里提示恢复失败,也就是恢复时,默认无法覆盖恢复数据,那么能否设置覆盖恢复呢?答案是可以的,就是使用--drop
参数来声明覆盖恢复数据:
[mongod@cs ~]$ mongorestore -uroot -p1234 --port 28020 --authenticationDatabase admin --drop /data/mongodb_data/backup/full_zip --gzip
[mongod@cs ~]$ mongo -uroot -p1234 --port 28020
> use t1
switched to db t1
> db.s1.count()
100
由查询结果可以发现,覆盖恢复数据也没问题。
注意,请谨慎使用--drop
参数。
从全库备份中恢复指定库
# 从全备中恢复指定库,如果从压缩备份中恢复,还需要携带 --gzip 如果覆盖恢复,需要添加参数 --drop
mongorestore -uroot -p1234 --port 28020 --authenticationDatabase admin -d t1 /data/mongodb_data/backup/full/t1
mongorestore -uroot -p1234 --port 28020 --authenticationDatabase admin -d t1 /data/mongodb_data/backup/full_zip/t1 --gzip
从全库备份中恢复指定库下的指定集合
# 从全备中恢复指定库下的指定集合,如果从压缩备份中恢复,还需要携带 --gzip 如果覆盖恢复,需要添加参数 --drop
mongorestore -uroot -p1234 --port 28020 --authenticationDatabase admin -d t1 -c s1 /data/mongodb_data/backup/full/t1/s1.bson
mongorestore -uroot -p1234 --port 28020 --authenticationDatabase admin -d t1 -c s1 /data/mongodb_data/backup/full_zip/t1/s1.bson.gz --gzip
上面演示的都是从全备数据中恢复数据,接下来在简要说说从备份的指定库、指定集合如何恢复数据,其实思路都是一样的。
从备份指定库或者指定集合中恢复数据
# 从备份的库中恢复数据到指定库,如果从压缩备份中恢复,还需要携带 --gzip 如果覆盖恢复,需要添加参数 --drop
mongorestore -uroot -p1234 --port 28020 --authenticationDatabase admin -d t1 --drop /data/mongodb_data/backup/t1
mongorestore -uroot -p1234 --port 28020 --authenticationDatabase admin -d t1 --drop /data/mongodb_data/backup/t1_zip --gzip
# 从备份的集合中恢复数据,如果从压缩备份中恢复,还需要携带 --gzip 如果覆盖恢复,需要添加参数 --drop
mongorestore -uroot -p1234 --port 28020 --authenticationDatabase admin -d t1 --drop /data/mongodb_data/backup/s1/t1/s1.bson
mongorestore -uroot -p1234 --port 28020 --authenticationDatabase admin -d t1 --drop /data/mongodb_data/backup/s1_zip/t1/s1.bson.gz --gzip