提交 1f67d39f 编写于 作者: J jackfrued

更新了数据库部分的文档

上级 6ed9e604
此差异已折叠。
......@@ -27,7 +27,7 @@
- [DB2](https://www.ibm.com/analytics/us/en/db2/) - IBM公司开发的、主要运行于Unix(包括IBM自家的[AIX](https://zh.wikipedia.org/wiki/AIX))、Linux、以及Windows服务器版等系统的关系数据库产品。DB2历史悠久且被认为是最早使用SQL的数据库产品,它拥有较为强大的商业智能功能。
- [SQL Server](https://www.microsoft.com/en-us/sql-server/) - 由Microsoft开发和推广的关系型数据库产品,最初适用于中小企业的数据管理,但是近年来它的应用范围有所扩展,部分大企业甚至是跨国公司也开始基于它来构建自己的数据管理系统。
- [MySQL](https://www.mysql.com/) - MySQL是开放源代码的,任何人都可以在GPL(General Public License)的许可下下载并根据个性化的需要对其进行修改。MySQL因为其速度、可靠性和适应性而备受关注。
- [PostgreSQL]() - 在BSD许可证下发行的开源代码的关系数据库产品。
- [PostgreSQL]() - 在BSD许可证下发行的开源代码的关系数据库产品。
### MySQL简介
......@@ -108,7 +108,7 @@
mysql -u root
```
修改超级管理员(root)的访问口令为hello_world_123。
修改超级管理员(root)的访问口令为i_LOVE_macos_123。
```SQL
use mysql;
......
## Django实战(03) - 静态资源和Ajax请求
基于前面两个章节讲解的知识,我们已经可以使用Django框架来实现Web应用的开发了。接下来我们就尝试实现一个投票应用,具体的需求是用户进入系统首先来到“登录页”;登录成功后可以查看到“学科介绍”页面,该页面显示了一个学校所开设的所有学科;通过点击某个学科,可以进入“讲师详情”页面,该页面展示了该学科所有讲师的详细情况,可以在该页面上给讲师点击“好评”或“差评”;对于未注册的用户,可以在登录页点击“新用户注册”进入“注册页”完成用户注册,注册成功或失败都会获得相应的提示信息,注册成功后会返回“登录页”
基于前面两个章节讲解的知识,我们已经可以使用Django框架来实现Web应用的开发了。接下来我们就尝试实现一个投票应用,具体的需求是用户进入应用首先查看到“学科介绍”页面,该页面显示了一个学校所开设的所有学科;通过点击某个学科,可以进入“老师介绍”页面,该页面展示了该学科所有老师的详细情况,可以在该页面上给老师点击“好评”或“差评”,但是会先跳转到“登录页”要求用户登录,登录成功才能投票;对于未注册的用户,可以在“登录页”点击“新用户注册”进入“注册页”完成用户注册,注册成功后会跳转到“登录页”,注册失败会获得相应的提示信息
### 准备工作
由于之前已经详细的讲解了如何创建Django项目以及项目的相关配置,因此我们略过这部分内容,唯一需要说明的是,我们将项目命名为hellodjango,在项目下创建了一个名为demo的应用。从“学科介绍”和“讲师详情”页面的需求,我们可以首先分析出两个业务实体,一个是学科,一个是讲师,二者之前是一对多关联。因此,我们首先修改应用demo下的models.py文件来定义数据模型。
由于之前已经详细的讲解了如何创建Django项目以及项目的相关配置,因此我们略过这部分内容,唯一需要说明的是,从上面对投票应用需求的描述中我们可以分析出三个业务实体:学科、老师和用户。学科和老师之间通常是一对多关联关系(一个学科有多个老师,一个老师通常只属于一个学科),用户因为要给老师投票,所以跟老师之间是多对多关联关系(一个用户可以给多个老师投票,一个老师也可以收到多个用户的投票)。首先修改应用下的models.py文件来定义数据模型,先给出学科和老师的模型。
```Python
from django.db import models
from django.db.models import PROTECT
class Subject(models.Model):
no = models.AutoField(primary_key=True, db_column='sno', verbose_name='编号')
name = models.CharField(max_length=50, db_column='sname', verbose_name='学科名称')
intro = models.CharField(max_length=511, db_column='sintro', verbose_name='学科介绍')
def __str__(self):
return self.name
class Meta(object):
db_table = 'tb_subject'
verbose_name = '学科'
verbose_name_plural = '学科'
class Teacher(models.Model):
no = models.AutoField(primary_key=True, db_column='tno', verbose_name='编号')
name = models.CharField(max_length=20, db_column='tname', verbose_name='姓名')
intro = models.CharField(max_length=1023, db_column='tintro', verbose_name='简介')
motto = models.CharField(max_length=255, db_column='tmotto', verbose_name='教学理念')
photo = models.CharField(max_length=511, db_column='tphoto', verbose_name='照片', null=True, blank=True)
subject = models.ForeignKey(Subject, db_column='sno', on_delete=PROTECT, related_name='+', verbose_name='所属学科')
manager = models.BooleanField(default=False, db_column='tmanager', verbose_name='是否主管')
good_count = models.IntegerField(default=0, db_column='tgcount', verbose_name='好评数')
bad_count = models.IntegerField(default=0, db_column='tbcount', verbose_name='差评数')
@property
def gcount(self):
return f'{self.good_count}' \
if self.good_count <= 999 else '999+'
@property
def bcount(self):
return f'{self.bad_count}' \
if self.bad_count <= 999 else '999+'
class Meta(object):
db_table = 'tb_teacher'
verbose_name = '讲师'
verbose_name_plural = '讲师'
```
模型定义完成后,可以通过“生成迁移”和“执行迁移”来完成关系型数据库中二维表的创建,当然这需要提前启动数据库服务器并创建好对应的数据库,同时我们在项目中已经安装了PyMySQL而且完成了相应的配置,这些内容此处不再赘述。
......@@ -61,25 +19,10 @@ class Teacher(models.Model):
...
```
完成模型迁移之后,我们可以通过下面的SQL语句来添加学科和师的数据。
完成模型迁移之后,我们可以通过下面的SQL语句来添加学科和师的数据。
```SQL
INSERT INTO `tb_subject`
(`sname`, `sintro`)
VALUES
('Python教学部', 'Python是一种面向对象的解释型计算机程序设计语言,由荷兰人Guido van Rossum于1989年发明,第一个公开发行版发行于1991年。' ),
('JavaEE教学部', 'Java是一门面向对象编程语言,不仅吸收了C++语言的各种优点,还摒弃了C++里难以理解的多继承、指针等概念,因此Java语言具有功能强大和简单易用两个特征。' ),
('HTML5教学部', 'HTML5 将成为 HTML、XHTML 以及 HTML DOM 的新标准。' );
INSERT INTO `tb_teacher`
(`tname`, `tintro`, `tmotto`, `tphoto`, `tmanager`, `sno`)
VALUES
('骆昊', '10年以上软硬件产品和系统设计、研发、架构和管理经验,2003年毕业于四川大学,四川大学Java技术俱乐部创始人,四川省优秀大学毕业生,在四川省网络通信技术重点实验室工作期间,参与了2项国家自然科学基金项目、1项中国科学院中长期研究项目和多项四川省科技攻关项目,在国际会议和国内顶级期刊上发表多篇论文(1篇被SCI收录,3篇被EI收录),大规模网络性能测量系统DMC-TS的设计者和开发者,perf-TTCN语言的发明者。国内最大程序员社区CSDN的博客专家,在Github上参与和维护了多个高质量开源项目,精通C/C++、Java、Python、R、Swift、JavaScript等编程语言,擅长OOAD、系统架构、算法设计、协议分析和网络测量,主持和参与过电子政务系统、KPI考核系统、P2P借贷平台等产品的研发,一直践行“用知识创造快乐”的教学理念,善于总结,乐于分享。', '教育是让受教育者体会用知识创造快乐的过程', 'images/ken.png', 1, 1),
('余小美', '5年以上移动互联网项目开发经验和教学经验,曾担任上市游戏公司高级软件研发工程师和移动端(iOS)技术负责人,参了多个企业级应用和游戏类应用的移动端开发和后台服务器开发,拥有丰富的开发经验和项目管理经验,以个人开发者和协作开发者的身份在苹果的AppStore上发布过多款App。精通Python、C、Objective-C、Swift等开发语言,熟悉iOS原生App开发、RESTful接口设计以及基于Cocos2d-x的游戏开发。授课条理清晰、细致入微,性格活泼开朗、有较强的亲和力,教学过程注重理论和实践的结合,在学员中有良好的口碑。', '每天叫醒你的不是闹钟而是梦想', 'images/linus.png', 0, 1),
('肖小帅', '10年以上互联网和移动互联网产品设计、研发、技术架构和项目管理经验,曾在中国移动、symbio、ajinga.com、万达信息等公司担任架构师、项目经理、技术总监等职务,长期为苹果、保时捷、耐克、沃尔玛等国际客户以及国内的政府机构提供信息化服务,主导的项目曾获得“世界科技先锋”称号,个人作品“许愿吧”曾在腾讯应用市场生活类App排名前3,拥有百万级用户群体,运营的公众号“卵石坊”是国内知名的智能穿戴设备平台。精通Python、C++、Java、Ruby、JavaScript等开发语言,主导和参与了20多个企业级项目(含国家级重大项目和互联网创新项目),涉及的领域包括政务、社交、电信、卫生和金融,有极为丰富的项目实战经验。授课深入浅出、条理清晰,善于调动学员的学习热情并帮助学员理清思路和方法。', '世上没有绝望的处境,只有对处境绝望的人', 'images/dennis.png', 0, 1),
('王大帅', '5年以上Python开发经验,先后参与了O2O商城、CRM系统、CMS平台、ERP系统等项目的设计与研发,曾在全国最大最专业的汽车领域相关服务网站担任Python高级研发工程师、项目经理等职务,擅长基于Python、Java、PHP等开发语言的企业级应用开发,全程参与了多个企业级应用从需求到上线所涉及的各种工作,精通Django、Flask等框架,熟悉基于微服务的企业级项目开发,拥有丰富的项目实战经验。善于用浅显易懂的方式在课堂上传授知识点,在授课过程中经常穿插企业开发的实际案例并分析其中的重点和难点,通过这种互动性极强的教学模式帮助学员找到解决问题的办法并提升学员的综合素质。', '不要给我说什么底层原理、框架内核!老夫敲代码就是一把梭!复制!黏贴!拿起键盘就是干!', NULL, 0, 1),
('何大富', '5年以上JavaEE项目开发和教学经验,参与过人力资源管理系统、电子教育产品在线商城、平安好医生App、平安好车主App等项目的设计与研发。擅长Java语言、面向对象编程、JavaEE框架、Web前端开发、数据库编程和Android应用开发,对新技术有着浓厚的兴趣和钻研精神,对微服务架构、虚拟化技术、区块链、边缘计算等领域都有自己独到的认识和见解,有丰富的项目经验和教学经验。授课时注重学习方法的引导,提倡以项目为导向的实战型教学,同时也注重基础知识的掌握和底层原理的理解,课堂氛围轻松幽默,能够把枯燥乏味的知识变成生动有趣的案例,帮助学员更快更好的掌握技术的要领,从事JavaEE教学工作以来,获得了学生潮水般的好评。', '每天撸代码,生活乐无边!', 'images/andrew.png', 0, 2),
('吴小富', '毕业于西南交通大学,高级软件研发工程师,10年以上的开发和培训经验。曾就职于华为赛门铁克科技有限公司,负责公司内部ERP系统的研发,参与和主导过多个大型门户网站、电子商务网站、电子政务系统以及多个企业级Web项目的设计和开发,同时负责过多门企业内训课程的研发与讲授,有着非常丰富的JavaEE项目开发经验和Web前端开发经验,精通C/C++、Java、PHP、JavaScript等开发语言,能够使用多种技术进行全栈开发。授课经验丰富、思路清晰、富有激情,对知识点的讲解由浅入深、深入浅出,能够通过实际开发的场景引导学员思考业务并理解相关技术,善于将多年的项目实战经验和企业内训经验融入课堂,通过理论联系实际的方式帮助学员迅速提升就业能力。', '人生的道路在态度的岔口一分为二', NULL, 1, 3);
```
接下来,我们就可以修改views.py文件,通过编写视图函数先实现“学科介绍”页面。
......@@ -87,10 +30,10 @@ VALUES
```Python
def show_subjects(request):
ctx = {'subjects_list': Subject.objects.all()}
return render(request, 'demo/subject.html', ctx)
return render(request, 'subject.html', ctx)
```
至此,我们还需要一个模板页,模板的配置以及模板页中模板语言的用法在之前已经进行过简要的介绍,如果不熟悉可以看看下面的代码,相信学会编写模板页并熟练的使用模板语言并不是一件困难的事情。
至此,我们还需要一个模板页,模板的配置以及模板页中模板语言的用法在之前已经进行过简要的介绍,如果不熟悉可以看看下面的代码,相信并不是一件困难的事情。
```HTML
<!DOCTYPE html>
......@@ -151,7 +94,7 @@ def show_teachers(request, no):
return render(request, 'demo/teacher.html', ctx)
```
接下来我们可以定制“师详情”的模板页。
接下来我们可以定制“师详情”的模板页。
```HTML
<!DOCTYPE html>
......@@ -214,7 +157,7 @@ def show_teachers(request, no):
</html>
```
请注意上面的模板页面,我们在第2行和`<img>`标签中使用了加载静态资源的模板指令,通过加载静态资源的指令我们可以显示师的头像。当然,我们还得创建放置静态资源的文件夹并在项目的配置文件中指明静态资源文件夹的所在以及静态资源的URL。
请注意上面的模板页面,我们在第2行和`<img>`标签中使用了加载静态资源的模板指令,通过加载静态资源的指令我们可以显示师的头像。当然,我们还得创建放置静态资源的文件夹并在项目的配置文件中指明静态资源文件夹的所在以及静态资源的URL。
```Shell
(venv)$ mkdir static
......@@ -241,7 +184,7 @@ STATIC_URL = '/static/'
接下来就可以实现“好评”和“差评”的功能了,很明显如果能够在不刷新页面的情况下实现这两个功能会带来更好的用户体验,因此我们考虑使用[Ajax](https://zh.wikipedia.org/wiki/AJAX)来实现“好评”和“差评”。
首先修改项目的urls.py文件,为“好评”和“差评”功能映射对应的URL,跟上面一样我们在URL中使用了占位符语法来绑定师的编号。
首先修改项目的urls.py文件,为“好评”和“差评”功能映射对应的URL,跟上面一样我们在URL中使用了占位符语法来绑定师的编号。
```Python
from django.contrib import admin
......
## 存储数据
### 数据缓存
通过[《网络数据采集和解析》](./02.数据采集和解析.md)一文,我们已经知道了如何从指定的页面中抓取数据,以及如何保存抓取的结果,但是我们没有考虑过这么一种情况,就是我们可能需要从已经抓取过的页面中提取出更多的数据,重新去下载这些页面对于规模不大的网站倒是问题也不大,但是如果能够把这些页面缓存起来,对应用的性能会有明显的改善。
### 使用NoSQL
#### Redis简介
Redis是REmote DIctionary Server的缩写,它是一个用ANSI C编写的高性能的key-value存储系统,与其他的key-value存储系统相比,Redis有以下一些特点(也是优点):
- Redis的读写性能极高,并且有丰富的特性(发布/订阅、事务、通知等)。
- Redis支持数据的持久化(RDB和AOF两种方式),可以将内存中的数据保存在磁盘中,重启的时候可以再次加载进行使用。
- Redis不仅仅支持简单的key-value类型的数据,同时还提供hash、list、set,zset、hyperloglog、geo等数据类型。
- Redis支持主从复制(实现读写分析)以及哨兵模式(监控master是否宕机并调整配置)。
#### Redis的安装和配置
可以使用Linux系统的包管理工具(如yum)来安装Redis,也可以通过在Redis的[官方网站](https://redis.io/)下载Redis的[源代码](http://download.redis.io/releases/redis-3.2.11.tar.gz)解压缩解归档之后进行构件安装。
```Shell
wget http://download.redis.io/releases/redis-3.2.11.tar.gz
gunzip redis-3.2.11.tar.gz
tar -xvf redis-3.2.11.tar
cd redis-3.2.11
make && make install
```
接下来我们将redis-3.2.11目录下的redis.conf配置文件复制到用户主目录下并修改配置文件(如果你对配置文件不是很有把握就不要直接修改而是先复制一份再修改这个副本)。
```Shell
cd ..
cp redis-3.2.11/redis.conf redis.conf
vim redis.conf
```
配置将Redis服务绑定到指定的IP地址和端口。
![](./res/redis-bind.png)
![](./res/redis-port.png)
配置底层有多少个数据库。
![](./res/redis-database.png)
配置Redis的持久化机制 - RDB。
![](./res/redis-save.png)
![](./res/redis-rdb.png)
配置Redis的持久化机制 - AOF。
![](./res/redis-aof.png)
配置访问Redis服务器的验证口令。
![](./res/redis-security.png)
配置Redis的主从复制,通过主从复制可以实现读写分离。
![](./res/redis-replication.png)
配置慢查询日志。
![](./res/redis-slow-log.png)
这样我们就完成了Redis的基本配置,如果对上面的东西感到困惑,可以先系统的了解一下Redis,[《Redis开发与运维》](https://item.jd.com/12121730.html)是一本不错的入门读物,而[《Redis实战》](https://item.jd.com/11791607.html)是不错的进阶读物。
#### Redis的服务器和客户端
接下来启动Redis服务器,可以将服务器放在后台去运行。
```Shell
redis-server redis.conf &
_.-``__ ''-._
_.-`` `. `_. ''-._ Redis 3.2.11 (00000000/0) 64 bit
.-`` .-```. ```\/ _.,_ ''-._
( ' , .-` | `, ) Running in standalone mode
|`-._`-...-` __...-.``-._|'` _.-'| Port: 6379
| `-._ `._ / _.-' | PID: 12345
`-._ `-._ `-./ _.-' _.-'
|`-._`-._ `-.__.-' _.-'_.-'|
| `-._`-._ _.-'_.-' | http://redis.io
`-._ `-._`-.__.-'_.-' _.-'
|`-._`-._ `-.__.-' _.-'_.-'|
| `-._`-._ _.-'_.-' |
`-._ `-._`-.__.-'_.-' _.-'
`-._ `-.__.-' _.-'
`-._ _.-'
`-.__.-'
```
接下来,我们尝试用Redis客户端去连接服务器。
```Shell
redis-cli -h 172.18.61.250 -p 6379
172.18.61.250:6379> auth 1qaz2wsx
OK
172.18.61.250:6379> ping
PONG
172.18.61.250:6379>
```
Redis有着非常丰富的数据类型,也有很多的命令来操作这些数据,具体的内容可以查看[Redis命令参考](http://redisdoc.com/),在这个网站上,除了Redis的命令参考,还有Redis的详细文档,其中包括了通知、事务、主从复制、持久化、哨兵、集群等内容。
```Shell
172.18.61.250:6379> set username admin
OK
172.18.61.250:6379> get username
"admin"
172.18.61.250:6379> hset student1 name hao
(integer) 0
172.18.61.250:6379> hset student1 age 38
(integer) 1
172.18.61.250:6379> hset student1 gender male
(integer) 1
172.18.61.250:6379> hgetall student1
1) "name"
2) "hao"
3) "age"
4) "38"
5) "gender"
6) "male"
172.18.61.250:6379> lpush num 1 2 3 4 5
(integer) 5
172.18.61.250:6379> lrange num 0 -1
1) "5"
2) "4"
3) "3"
4) "2"
5) "1"
172.18.61.250:6379> sadd fruits apple banana orange apple grape grape
(integer) 4
172.18.61.250:6379> scard fruits
(integer) 4
172.18.61.250:6379> smembers fruits
1) "grape"
2) "orange"
3) "banana"
4) "apple"
172.18.61.250:6379> zadd scores 90 zhao 78 qian 66 sun 95 lee
(integer) 4
172.18.61.250:6379> zrange scores 0 -1
1) "sun"
2) "qian"
3) "zhao"
4) "lee"
172.18.61.250:6379> zrevrange scores 0 -1
1) "lee"
2) "zhao"
3) "qian"
4) "sun"
```
#### 在Python程序中使用Redis
### 存储海量数据
可以使用pip安装redis模块。redis模块的核心是名为Redis的类,该类的对象代表一个Redis客户端,通过该客户端可以向Redis服务器发送命令并获取执行的结果。上面我们在Redis客户端中使用的命令基本上就是Redis对象可以接收的消息,所以如果了解了Redis的命令就可以在Python中玩转Redis
数据持久化的首选方案应该是关系型数据库,关系型数据库的产品很多,包括:Oracle、MySQL、SQLServer、PostgreSQL等。如果要存储海量的低价值数据,文档数据库也是不错的选择,MongoDB是文档数据库中的佼佼者,之前我们已经讲解过MongDB的相关知识,在此不再进行赘述
```Shell
pip3 install redis
python3
```
```Python
>>> import redis
>>> client = redis.Redis(host='1.2.3.4', port=6379, password='1qaz2wsx')
>>> client.set('username', 'admin')
True
>>> client.hset('student', 'name', 'hao')
1
>>> client.hset('student', 'age', 38)
1
>>> client.keys('*')
[b'username', b'student']
>>> client.get('username')
b'admin'
>>> client.hgetall('student')
{b'name': b'hao', b'age': b'38'}
```
#### MongoDB简介
MongoDB是2009年问世的一个面向文档的数据库管理系统,由C++语言编写,旨在为Web应用提供可扩展的高性能数据存储解决方案。虽然在划分类别的时候后,MongoDB被认为是NoSQL的产品,但是它更像一个介于关系数据库和非关系数据库之间的产品,在非关系数据库中它功能最丰富,最像关系数据库。
MongoDB将数据存储为一个文档,一个文档由一系列的“键值对”组成,其文档类似于JSON对象,但是MongoDB对JSON进行了二进制处理(能够更快的定位key和value),因此其文档的存储格式称为BSON。关于JSON和BSON的差别大家可以看看MongoDB官方网站的文章[《JSON and BSON》](https://www.mongodb.com/json-and-bson)
目前,MongoDB已经提供了对Windows、MacOS、Linux、Solaris等多个平台的支持,而且也提供了多种开发语言的驱动程序,Python当然是其中之一。
#### MongoDB的安装和配置
可以从MongoDB的[官方下载链接](https://www.mongodb.com/download-center#community)下载MongoDB,官方为Windows系统提供了一个Installer程序,而Linux和MacOS则提供了压缩文件。下面简单说一下Linux系统如何安装和配置MongoDB。
```Shell
wget https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-amazon-3.6.5.tgz
gunzip mongodb-linux-x86_64-amazon-3.6.5.tgz
mkdir mongodb-3.6.5
tar -xvf mongodb-linux-x86_64-amazon-3.6.5.tar --strip-components 1 -C mongodb-3.6.5/
export PATH=$PATH:~/mongodb-3.6.5/bin
mkdir -p /data/db
mongod --bind_ip 172.18.61.250
2018-06-03T18:03:28.232+0800 I CONTROL [initandlisten] MongoDB starting : pid=1163 port=27017 dbpath=/data/db 64-bit host=iZwz97tbgo9lkabnat2lo8Z
2018-06-03T18:03:28.232+0800 I CONTROL [initandlisten] db version v3.6.5
2018-06-03T18:03:28.232+0800 I CONTROL [initandlisten] git version: a20ecd3e3a174162052ff99913bc2ca9a839d618
2018-06-03T18:03:28.232+0800 I CONTROL [initandlisten] OpenSSL version: OpenSSL 1.0.0-fips29 Mar 2010
...
2018-06-03T18:03:28.945+0800 I NETWORK [initandlisten] waiting for connections on port 27017
```
> 说明:上面的操作中,export命令是设置PATH环境变量,这样可以在任意路径下执行mongod来启动MongoDB服务器。MongoDB默认保存数据的路径是/data/db目录,为此要提前创建该目录。此外,在使用mongod启动MongoDB服务器时,—bind_ip参数用来将服务绑定到指定的IP地址,也可以用—port参数来指定端口,默认端口为27017。
#### MongoDB基本概念
我们通过与关系型数据库进行对照的方式来说明MongoDB中的一些概念。
| SQL | MongoDB | 解释(SQL/MongoDB) |
| ----------- | ----------- | ---------------------- |
| database | database | 数据库/数据库 |
| table | collection | 二维表/集合 |
| row | document | 记录(行)/文档 |
| column | field | 字段(列)/域 |
| index | index | 索引/索引 |
| table joins | --- | 表连接/嵌套文档 |
| primary key | primary key | 主键/主键(`_id`字段) |
#### 通过Shell操作MongoDB
启动服务器后可以使用交互式环境跟服务器通信,如下所示。
```shell
mongo --host 172.18.61.250
MongoDB shell version v3.6.5
connecting to: mongodb://172.18.61.250:27017/
...
>
```
1. 查看、创建和删除数据库。
```JavaScript
> // 显示所有数据库
> show dbs
admin 0.000GB
config 0.000GB
local 0.000GB
> // 创建并切换到school数据库
> use school
switched to db school
> // 删除当前数据库
> db.dropDatabase()
{ "ok" : 1 }
>
```
2. 创建、删除和查看集合。
```JavaScript
> // 创建并切换到school数据库
> use school
switched to db school
> // 创建colleges集合
> db.createCollection('colleges')
{ "ok" : 1 }
> // 创建students集合
> db.createCollection('students')
{ "ok" : 1 }
> // 查看所有集合
> show collections
colleges
students
> // 删除colleges集合
> db.colleges.drop()
true
>
```
> 说明:在MongoDB中插入文档时如果集合不存在会自动创建集合,所以也可以按照下面的方式通过创建文档来创建集合。
3. 文档的CRUD操作。
```JavaScript
> // 向students集合插入文档
> db.students.insert({stuid: 1001, name: '骆昊', age: 38})
WriteResult({ "nInserted" : 1 })
> // 向students集合插入文档
> db.students.save({stuid: 1002, name: '王大锤', tel: '13012345678', gender: '男'})
WriteResult({ "nInserted" : 1 })
> // 查看所有文档
> db.students.find()
{ "_id" : ObjectId("5b13c72e006ad854460ee70b"), "stuid" : 1001, "name" : "骆昊", "age" : 38 }
{ "_id" : ObjectId("5b13c790006ad854460ee70c"), "stuid" : 1002, "name" : "王大锤", "tel" : "13012345678", "gender" : "男" }
> // 更新stuid为1001的文档
> db.students.update({stuid: 1001}, {'$set': {tel: '13566778899', gender: '男'}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> // 插入或更新stuid为1003的文档
> db.students.update({stuid: 1003}, {'$set': {name: '白元芳', tel: '13022223333', gender: '男'}}, upsert=true)
WriteResult({
"nMatched" : 0,
"nUpserted" : 1,
"nModified" : 0,
"_id" : ObjectId("5b13c92dd185894d7283efab")
})
> // 查询所有文档
> db.students.find().pretty()
{
"_id" : ObjectId("5b13c72e006ad854460ee70b"),
"stuid" : 1001,
"name" : "骆昊",
"age" : 38,
"gender" : "男",
"tel" : "13566778899"
}
{
"_id" : ObjectId("5b13c790006ad854460ee70c"),
"stuid" : 1002,
"name" : "王大锤",
"tel" : "13012345678",
"gender" : "男"
}
{
"_id" : ObjectId("5b13c92dd185894d7283efab"),
"stuid" : 1003,
"gender" : "男",
"name" : "白元芳",
"tel" : "13022223333"
}
> // 查询stuid大于1001的文档
> db.students.find({stuid: {'$gt': 1001}}).pretty()
{
"_id" : ObjectId("5b13c790006ad854460ee70c"),
"stuid" : 1002,
"name" : "王大锤",
"tel" : "13012345678",
"gender" : "男"
}
{
"_id" : ObjectId("5b13c92dd185894d7283efab"),
"stuid" : 1003,
"gender" : "男",
"name" : "白元芳",
"tel" : "13022223333"
}
> // 查询stuid大于1001的文档只显示name和tel字段
> db.students.find({stuid: {'$gt': 1001}}, {_id: 0, name: 1, tel: 1}).pretty()
{ "name" : "王大锤", "tel" : "13012345678" }
{ "name" : "白元芳", "tel" : "13022223333" }
> // 查询name为“骆昊”或者tel为“13022223333”的文档
> db.students.find({'$or': [{name: '骆昊'}, {tel: '13022223333'}]}, {_id: 0, name: 1, tel: 1}).pretty()
{ "name" : "骆昊", "tel" : "13566778899" }
{ "name" : "白元芳", "tel" : "13022223333" }
> // 查询学生文档跳过第1条文档只查1条文档
> db.students.find().skip(1).limit(1).pretty()
{
"_id" : ObjectId("5b13c790006ad854460ee70c"),
"stuid" : 1002,
"name" : "王大锤",
"tel" : "13012345678",
"gender" : "男"
}
> // 对查询结果进行排序(1表示升序,-1表示降序)
> db.students.find({}, {_id: 0, stuid: 1, name: 1}).sort({stuid: -1})
{ "stuid" : 1003, "name" : "白元芳" }
{ "stuid" : 1002, "name" : "王大锤" }
{ "stuid" : 1001, "name" : "骆昊" }
> // 在指定的一个或多个字段上创建索引
> db.students.ensureIndex({name: 1})
{
"createdCollectionAutomatically" : false,
"numIndexesBefore" : 1,
"numIndexesAfter" : 2,
"ok" : 1
}
>
```
使用MongoDB可以非常方便的配置数据复制,通过冗余数据来实现数据的高可用以及灾难恢复,也可以通过数据分片来应对数据量迅速增长的需求。关于MongoDB更多的操作可以查阅[官方文档](https://mongodb-documentation.readthedocs.io/en/latest/) ,同时推荐大家阅读Kristina Chodorow写的[《MongoDB权威指南》](http://www.ituring.com.cn/book/1172)
####在Python程序中操作MongoDB
可以通过pip安装pymongo来实现对MongoDB的操作。
```Shell
pip3 install pymongo
python3
```
```Python
>>> from pymongo import MongoClient
>>> client = MongoClient('mongodb://120.77.222.217:27017')
>>> db = client.school
>>> for student in db.students.find():
... print('学号:', student['stuid'])
... print('姓名:', student['name'])
... print('电话:', student['tel'])
...
学号: 1001.0
姓名: 骆昊
电话: 13566778899
学号: 1002.0
姓名: 王大锤
电话: 13012345678
学号: 1003.0
姓名: 白元芳
电话: 13022223333
>>> db.students.find().count()
3
>>> db.students.remove()
{'n': 3, 'ok': 1.0}
>>> db.students.find().count()
0
>>> coll = db.students
>>> from pymongo import ASCENDING
>>> coll.create_index([('name', ASCENDING)], unique=True)
'name_1'
>>> coll.insert_one({'stuid': int(1001), 'name': '骆昊', 'gender': True})
<pymongo.results.InsertOneResult object at 0x1050cc6c8>
>>> coll.insert_many([{'stuid': int(1002), 'name': '王大锤', 'gender': False}, {'stuid': int(1003), 'name': '白元芳', 'gender': True}])
<pymongo.results.InsertManyResult object at 0x1050cc8c8>
>>> for student in coll.find({'gender': True}):
... print('学号:', student['stuid'])
... print('姓名:', student['name'])
... print('性别:', '男' if student['gender'] else '女')
...
学号: 1001
姓名: 骆昊
性别: 男
学号: 1003
姓名: 白元芳
性别: 男
>>>
```
### 数据缓存
关于PyMongo更多的知识可以通过它的[官方文档](https://api.mongodb.com/python/current/tutorial.html)进行了解
通过[《网络数据采集和解析》](./02.数据采集和解析.md)一文,我们已经知道了如何从指定的页面中抓取数据,以及如何保存抓取的结果,但是我们没有考虑过这么一种情况,就是我们可能需要从已经抓取过的页面中提取出更多的数据,重新去下载这些页面对于规模不大的网站倒是问题也不大,但是如果能够把这些页面缓存起来,对应用的性能会有明显的改善。可以使用Redis来提供高速缓存服务,关于Redis的知识,我们在[《NoSQL入门》](../Day36-40/NoSQL入门.md)一文中已经做过简要的介绍
### 实例 - 缓存知乎发现上的链接和页面代码
......@@ -493,7 +64,3 @@ if __name__ == '__main__':
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册