139MongoDB 数据库入门实战--数据的备份与恢复

数据的备份与恢复

实验准备
打开实验环境,在终端输入如下命令启动 MongoDB 服务,进入命令行交互客户端:

$ cd
$ sudo service mongodb start
$ mongo

这里打开交互客户端是为了验证数据迁移的结果。

数据库的备份与恢复

在 MongoDB 客户端中查看目前有哪些数据库:

> show dbs
admin      0.000GB
challenge  0.000GB
config     0.000GB
learn      0.000GB
local      0.000GB
query      0.000GB
shiyanlou  0.000GB
>

接下来我们使用 shiyanlou 数据库进行学习,查看其中的集合和文档:

> use shiyanlou
switched to db shiyanlou
> show collections
player
> db.player.find()
{ "_id" : ObjectId("5e4b6d358b5daaaae4d74f89"), "name" : "Wade", "age" : 34, "addr" : [ "Mim", "Chi" ] }
{ "_id" : ObjectId("5e4b7ab4e009482777d42425"), "name" : "Kobe", "age" : 37, "addr" : [ "Tor", "Los" ] }
>

数据库的备份

在 Mongodb 中我们使用 mongodump 命令来备份 MongoDB 数据。该命令可以导出数据库的所有集合到指定目录中。
mongodump 命令的格式如下:

$ mongodump -h dbhost -d dbname -o dbdirectory

-h 也可以写作 --host ,为主机名和端口号,默认为 localhost:27017 或者 127.0.0.1:27017
-d 也可以写作 --db ,指定数据库名字
-o 也可以写作 --out ,指定备份目录

打开一个新的终端标签,切换到 /home/shiyanlou/Code 目录:

$ cd ~/Code

执行如下命令即可将 shiyanlou 数据库中的全部集合(其实只有一个)数据存储到当前目录下的 shiyanlou 目录:

shiyanlou:Code/ $ mongodump -h localhost:27017 -d shiyanlou -o .
2020-02-21T11:09:46.731+0800    writing shiyanlou.player to
2020-02-21T11:09:46.750+0800    done dumping shiyanlou.player (2 documents)
shiyanlou:Code/ $ ll
总用量 4.0K
drwxr-xr-x 2 shiyanlou shiyanlou 4.0K 2月  21 11:09 shiyanlou
shiyanlou:Code/ $ tree shiyanlou
shiyanlou
├── player.bson
└── player.metadata.json

0 directories, 2 files
shiyanlou:Code/ $

如上所示,执行 mongodump 命令后,当前目录下出现了 shiyanlou 目录,这个目录结构就是存储 shiyanlou 数据库的目录。新增目录的名字与数据库名一致。其中 -o 选项后面的 . 表示当前目录,也可以规定一个目录,比如 test :

shiyanlou:Code/ $ mongodump -h localhost:27017 -d shiyanlou -o test
2020-02-21T11:12:09.171+0800    writing shiyanlou.player to
2020-02-21T11:12:09.200+0800    done dumping shiyanlou.player (2 documents)
shiyanlou:Code/ $ ll
总用量 8.0K
drwxr-xr-x 2 shiyanlou shiyanlou 4.0K 2月  21 11:09 shiyanlou
drwxr-xr-x 3 shiyanlou shiyanlou 4.0K 2月  21 11:12 test
shiyanlou:Code/ $ tree test/
test/
└── shiyanlou
    ├── player.bson
    └── player.metadata.json

1 directory, 2 files
shiyanlou:Code/ $

这样的话,会在当前目录下新建 test 目录,test 目录里面是存储数据库的目录结构 shiyanlou 。
操作截图如下:


image.png

数据库的恢复

我们可以使用 mongorestore 命令来恢复数据库,也就是将上面备份得到的数据库目录结构导入到数据库中。
mongorestore 命令的格式如下:

$ mongorestore -h host -d dbname dir

-h 也可以写作 --host ,为主机名和端口号,默认为 localhost:27017 或者 127.0.0.1:27017
-d 也可以写作 --db ,指定数据库名字
dir 最后一个参数指定备份的目录

现在执行如下命令将当前目录下的 shiyanlou 目录导入到数据库中,这会新建一个数据库。因为目前已经存在 shiyanlou 数据库,所以我们新建一个 s1 数据库,将 shiyanlou 目录导入。
命令如下:

$ mongorestore -h localhost:27017 -d s1 shiyanlou

操作截图如下:


image.png

此时我们切回到 MongoDB 客户端查看操作结果:

> show dbs
admin      0.000GB
challenge  0.000GB
config     0.000GB
learn      0.000GB
local      0.000GB
query      0.000GB
s1         0.000GB
shiyanlou  0.000GB
> use s1
switched to db s1
> show collections
player
> db.player.find()
{ "_id" : ObjectId("5e4b6d358b5daaaae4d74f89"), "name" : "Wade", "age" : 34, "addr" : [ "Mim", "Chi" ] }
{ "_id" : ObjectId("5e4b7ab4e009482777d42425"), "name" : "Kobe", "age" : 37, "addr" : [ "Tor", "Los" ] }
>

一如预期,确实新增了 s1 数据库,且其中有一个 player 集合,集合中的数据与 shiyanlou.player 集合一致。

选择部分集合备份

有些时候,我们不想备份一个数据库里的全部集合。在使用 mongodump 命令的时候,可以增加一个 -c 选项选择某个集合进行备份:

$ mongodump -h dbhost -d dbname -c collection -o dbdirectory

-c 也可以写作 --collection ,指定集合

当前 MongoDB 中的 query 数据库里有两个集合,我们使用这个数据库来演示:

> show dbs
admin      0.000GB
challenge  0.000GB
config     0.000GB
learn      0.000GB
local      0.000GB
query      0.000GB
s1         0.000GB
shiyanlou  0.000GB
> use query
switched to db query
> show collections
stu
type
>

备份数据库 query ,且只备份 stu 集合:

shiyanlou:Code/ $ mongodump -h localhost:27017 -d query -c stu -o .
2020-02-21T11:29:31.801+0800    writing query.stu to
2020-02-21T11:29:31.841+0800    done dumping query.stu (7 documents)
shiyanlou:Code/ $ ll
总用量 12K
drwxr-xr-x 2 shiyanlou shiyanlou 4.0K 2月  21 11:29 query
drwxr-xr-x 2 shiyanlou shiyanlou 4.0K 2月  21 11:09 shiyanlou
drwxr-xr-x 3 shiyanlou shiyanlou 4.0K 2月  21 11:12 test
shiyanlou:Code/ $

检查备份结果,就要将新增的 query 目录导入到数据库中,指定新增数据库为 q1 :

$ mongorestore -h localhost:27017 -d q1 query

在 MongoDB 客户端中查看操作结果:

> show dbs
admin      0.000GB
challenge  0.000GB
config     0.000GB
learn      0.000GB
local      0.000GB
q1         0.000GB
query      0.000GB
s1         0.000GB
shiyanlou  0.000GB
> use q1
switched to db q1
> show collections
stu
> db.stu.find()
{ "_id" : ObjectId("5e4df26740faabaac0fd3de6"), "name" : "大红", "gender" : "男", "语文" : 83, "数学" : 81 }
{ "_id" : ObjectId("5e4df26740faabaac0fd3de7"), "name" : "大黄", "gender" : "女", "语文" : 83, "数学" : 20 }
{ "_id" : ObjectId("5e4df26740faabaac0fd3de8"), "name" : "大蓝", "gender" : "男", "语文" : 84, "数学" : 99 }
{ "_id" : ObjectId("5e4df26740faabaac0fd3de9"), "name" : "大绿", "gender" : "女", "语文" : 85, "数学" : 34 }
{ "_id" : ObjectId("5e4df26740faabaac0fd3dea"), "name" : "大橙", "gender" : "男", "语文" : 86, "数学" : 88 }
{ "_id" : ObjectId("5e4df26740faabaac0fd3deb"), "name" : "大青", "gender" : "女", "语文" : 87, "数学" : 93 }
{ "_id" : ObjectId("5e4df26740faabaac0fd3dec"), "name" : "大紫", "gender" : "男", "语文" : 99, "数学" : 20 }
>

果然新增的 q1 数据库中只有 stu 集合,且集合中的数据与 query.stu 集合一致。
数据库的备份与恢复操作就是以上这些,总结起来就是 mongodump 与 mongorestore 命令的使用。

集合的备份与恢复

集合的备份与恢复指的是针对一个集合中的文档进行备份,备份数据的文件格式有两种:JSON 和 CSV 。其中默认的备份格式为 JSON 。
接下来我们使用 query 数据库的 stu 集合分别介绍两种不同的文件格式的备份与恢复方法。
该集合中的内容如下:

> use query
switched to db query
> db.stu.find()
{ "_id" : ObjectId("5e4df26740faabaac0fd3de6"), "name" : "大红", "gender" : "男", "语文" : 83, "数学" : 81 }
{ "_id" : ObjectId("5e4df26740faabaac0fd3de7"), "name" : "大黄", "gender" : "女", "语文" : 83, "数学" : 20 }
{ "_id" : ObjectId("5e4df26740faabaac0fd3de8"), "name" : "大蓝", "gender" : "男", "语文" : 84, "数学" : 99 }
{ "_id" : ObjectId("5e4df26740faabaac0fd3de9"), "name" : "大绿", "gender" : "女", "语文" : 85, "数学" : 34 }
{ "_id" : ObjectId("5e4df26740faabaac0fd3dea"), "name" : "大橙", "gender" : "男", "语文" : 86, "数学" : 88 }
{ "_id" : ObjectId("5e4df26740faabaac0fd3deb"), "name" : "大青", "gender" : "女", "语文" : 87, "数学" : 93 }
{ "_id" : ObjectId("5e4df26740faabaac0fd3dec"), "name" : "大紫", "gender" : "男", "语文" : 99, "数学" : 20 }
>

使用 JSON 文件备份与恢复

导出数据
备份集合的操作命令是 mongoexport ,格式如下:

$ mongoexport -h host -d dbname -c collection --type json/csv -o file

-h 也可以写作 --host ,为主机名和端口号,默认为 localhost:27017 或者 127.0.0.1:27017
-d 也可以写作 --db ,指定数据库名字
-c 也可以写作 --collection ,指定集合名字
--type 指定导出文件的格式,有 json 和 csv 两种选择,默认为 json 格式
-o 也可以写作 --out ,指定备份目录

现在将 query 数据库的 stu 集合导出到 stu.json 文件,格式为 json ,默认可以省略 --type 选项。操作如下:

shiyanlou:Code/ $ mongoexport -h localhost:27017 -d query -c stu -o stu.json
2020-02-21T11:47:27.436+0800    connected to: localhost:27017
2020-02-21T11:47:27.441+0800    exported 7 records
shiyanlou:Code/ $ ll
总用量 16K
drwxr-xr-x 2 shiyanlou shiyanlou 4.0K 2月  21 11:29 query
drwxr-xr-x 2 shiyanlou shiyanlou 4.0K 2月  21 11:09 shiyanlou
-rw-r--r-- 1 shiyanlou shiyanlou  721 2月  21 11:47 stu.json
drwxr-xr-x 3 shiyanlou shiyanlou 4.0K 2月  21 11:12 test
shiyanlou:Code/ $ cat stu.json
{"_id":{"$oid":"5e4df26740faabaac0fd3de6"},"name":"大红","gender":"男","语文":83.0,"数学":81.0}
{"_id":{"$oid":"5e4df26740faabaac0fd3de7"},"name":"大黄","gender":"女","语文":83.0,"数学":20.0}
{"_id":{"$oid":"5e4df26740faabaac0fd3de8"},"name":"大蓝","gender":"男","语文":84.0,"数学":99.0}
{"_id":{"$oid":"5e4df26740faabaac0fd3de9"},"name":"大绿","gender":"女","语文":85.0,"数学":34.0}
{"_id":{"$oid":"5e4df26740faabaac0fd3dea"},"name":"大橙","gender":"男","语文":86.0,"数学":88.0}
{"_id":{"$oid":"5e4df26740faabaac0fd3deb"},"name":"大青","gender":"女","语文":87.0,"数学":93.0}
{"_id":{"$oid":"5e4df26740faabaac0fd3dec"},"name":"大紫","gender":"男","语文":99.0,"数学":20.0}
shiyanlou:Code/ $

操作截图:

image.png

导入数据
将文件中的数据导入到集合中使用 mongoimport 命令,格式如下:

$ mongoimport -h host -d dbname -c collection --file file

-h 也可以写作 --host ,为主机名和端口号,默认为 localhost:27017 或者 127.0.0.1:27017
-d 也可以写作 --db ,指定数据库名字
-c 也可以写作 --collection ,指定集合名字
--file 指定导入的文件

现在将当前目录下的 stu.json 文件导入到 query 数据库的 stu1 集合中:

$ mongoimport -h localhost:27017 -d query -c stu1 --file stu.json

切换到 MongoDB 数据库中查看结果:

> use query
switched to db query
> show collections
stu
stu1
type
> db.stu1.find()
{ "_id" : ObjectId("5e4df26740faabaac0fd3de6"), "name" : "大红", "gender" : "男", "语文" : 83, "数学" : 81 }
{ "_id" : ObjectId("5e4df26740faabaac0fd3de7"), "name" : "大黄", "gender" : "女", "语文" : 83, "数学" : 20 }
{ "_id" : ObjectId("5e4df26740faabaac0fd3de8"), "name" : "大蓝", "gender" : "男", "语文" : 84, "数学" : 99 }
{ "_id" : ObjectId("5e4df26740faabaac0fd3de9"), "name" : "大绿", "gender" : "女", "语文" : 85, "数学" : 34 }
{ "_id" : ObjectId("5e4df26740faabaac0fd3dea"), "name" : "大橙", "gender" : "男", "语文" : 86, "数学" : 88 }
{ "_id" : ObjectId("5e4df26740faabaac0fd3deb"), "name" : "大青", "gender" : "女", "语文" : 87, "数学" : 93 }
{ "_id" : ObjectId("5e4df26740faabaac0fd3dec"), "name" : "大紫", "gender" : "男", "语文" : 99, "数学" : 20 }
>

可以看到 query 数据库中新增了 stu1 集合,且集合中的数据与 query.stu 集合一致。

使用 CSV 文件备份与恢复

导出数据
与 JSON 文件不同的是,CSV 文件存在标题行。也就是在备份的时候,自动将文档的字段写入到文件的第一行。备份 CSV 文件需要使用 --type 选项指定备份格式。
现在将 query 数据库的 stu 集合备份到 stu.csv 文件中:

$ mongoexport -h localhost:27017 -d query -c stu1 \
> --type csv -f _id,name,gender,语文,数学 -o stu.csv

操作截图如下:

image.png

需要注意的是,如果选择 --type csv 格式,必须在后面添加 -f 选项,选项后面是导出的文档字段名,多个字段名用逗号隔开,逗号后面不允许有空格。
导入数据
导入数据也是使用 mongoimport 命令,与 JSON 格式的命令差不多,唯一的区别就是需要指定文件类型。此外还需要注意的是 CSV 文件的标题行,如果文件的第一行为标题行,需要增加 --headline 选项将其忽略。
现在将 stu.csv 文件导入到 query 数据库的 stu2 集合中:

$ mongoimport -h localhost:27017 -d query -c stu2 \
> --type csv --headerline --file stu.csv

注意此处因为使用了 --headerline 选项,MongoDB 会剪切文件的第一行,并从中读取字段名,在创建新的 stu2 集合时,会自动将数据按照顺序写入到相应的字段中。
在 MongoDB 客户端中查看操作结果:

> show collections
stu
stu1
stu2
type
> db.stu2.find()
{ "_id" : "ObjectId(5e4df26740faabaac0fd3de6)", "name" : "大红", "gender" : "男", "语文" : 83, "数学" : 81 }
{ "_id" : "ObjectId(5e4df26740faabaac0fd3de7)", "name" : "大黄", "gender" : "女", "语文" : 83, "数学" : 20 }
{ "_id" : "ObjectId(5e4df26740faabaac0fd3de8)", "name" : "大蓝", "gender" : "男", "语文" : 84, "数学" : 99 }
{ "_id" : "ObjectId(5e4df26740faabaac0fd3de9)", "name" : "大绿", "gender" : "女", "语文" : 85, "数学" : 34 }
{ "_id" : "ObjectId(5e4df26740faabaac0fd3dea)", "name" : "大橙", "gender" : "男", "语文" : 86, "数学" : 88 }
{ "_id" : "ObjectId(5e4df26740faabaac0fd3deb)", "name" : "大青", "gender" : "女", "语文" : 87, "数学" : 93 }
{ "_id" : "ObjectId(5e4df26740faabaac0fd3dec)", "name" : "大紫", "gender" : "男", "语文" : 99, "数学" : 20 }
>

没有标题行的 CSV 文件
终端执行如下命令复制 stu.csv 文件中的内容到 stu1.csv 文件,并删掉第 1 行:

$ cat stu.csv | sed '1d' > stu1.csv

操作截图如下:


image.png

现在要将 stu1.csv 导入到 query 数据库的 stu3 集合中,因为没有标题行,所以在 --type 后面需要增加 -f 选项提供字段值:

$ mongoimport -h localhost:27017 -d query -c stu3 \
> --type csv -f _id,name,gender,语文,数学 --file stu1.csv

在 MongoDB 客户端中查看操作结果:

> show collections
stu
stu1
stu2
stu3
type
> db.stu3.find()
{ "_id" : "ObjectId(5e4df26740faabaac0fd3de6)", "name" : "大红", "gender" : "男", "语文" : 83, "数学" : 81 }
{ "_id" : "ObjectId(5e4df26740faabaac0fd3de7)", "name" : "大黄", "gender" : "女", "语文" : 83, "数学" : 20 }
{ "_id" : "ObjectId(5e4df26740faabaac0fd3de8)", "name" : "大蓝", "gender" : "男", "语文" : 84, "数学" : 99 }
{ "_id" : "ObjectId(5e4df26740faabaac0fd3de9)", "name" : "大绿", "gender" : "女", "语文" : 85, "数学" : 34 }
{ "_id" : "ObjectId(5e4df26740faabaac0fd3dea)", "name" : "大橙", "gender" : "男", "语文" : 86, "数学" : 88 }
{ "_id" : "ObjectId(5e4df26740faabaac0fd3deb)", "name" : "大青", "gender" : "女", "语文" : 87, "数学" : 93 }
{ "_id" : "ObjectId(5e4df26740faabaac0fd3dec)", "name" : "大紫", "gender" : "男", "语文" : 99, "数学" : 20 }
>

挑战:数据查询与排序

本次挑战需要大家下载 JSON 文件,将其导入到数据库中,并从数据库中读取数据进行排序处理。
首先打开挑战环境,在终端启动 MongoDB 服务:

$ cd ~/Code
$ sudo service mongodb start

执行如下命令下载 JSON 文件到 Code 目录下:

$ wget https://labfile.oss.aliyuncs.com/courses/1364/users.json

这是一些用户完成挑战的数据。文件中共有 20 条数据,每条数据有 4 个字段,分别是:
user_id:用户 ID
challenge_id:挑战的 ID
score:用户完成本次挑战得到的分数
submit_time:用户完成本次挑战花费的时间
挑战要求
1、将 users.json 文件中的数据导入到 shiyanlou 数据库的 users 集合中。
2、在当前目录下创建 sort.py 文件,写入以下代码:

import sys
from pymongo import MongoClient

client = MongoClient(host='localhost', port=27017)
db = client.shiyanlou

def get_rank(user_id):
    # TODO

if __name__ == '__main__':
    user_id = int(sys.argv[-1])
    print(get_rank(user_id))

3、完善 sort.py 文件中的 get_rank 函数,让函数可以正确返回 user_id 对应的用户排名、总分数和总时间。
注意事项
Python3 、MongoDB 、PyMongo 均无需下载,挑战环境中已经安装了它们
每个用户有多条记录,所得的分数和花费的时间为多条记录的总和
排名规则首先按分数排名,如果分数相同则花费的总时间越少则排名越高
完成后,终端执行程序的操作如下:

image.png

参考答案

import sys
from pymongo import MongoClient
from bson.son import SON


def get_rank(user_id):
    client = MongoClient('localhost', 27017)
    users = client.shiyanlou.users

    s = users.aggregate([
        {'$group': {
            '_id': '$user_id',
            'sum_score': {'$sum': '$score'},
            'sum_minutes': {'$sum': '$submit_time'}
        }},
        {'$sort':
            SON([
                ('sum_score', -1),
                ('sum_minutes', 1)
            ])
        }
    ])

    for i, j in enumerate(s, 1):
        if j['_id'] == user_id:
            return i, j['sum_score'], j['sum_minutes']


if __name__ == '__main__':
    user_id = sys.argv[1]
    print(get_rank(int(user_id)))

你可能感兴趣的:(139MongoDB 数据库入门实战--数据的备份与恢复)