目录
数据库即特殊的文件,存储着需要的数据。
查看数据库排名:DB-Engines Ranking - popularity ranking of database management systems
RDBMS和数据库的关系
RDBMS即关系型数据库管理系统,数据库本质是文件,RDBMS可以理解为管理这些文件的系统。
把cmd当客户端,其和服务端的通信也是通过socket。
SQL
SQL是结构化查询语言,是一种用来操作RDBMS的数据库语言,当前关系型数据库都支持使用SQL语言进行操作,也就是说可以通过 SQL 操作 oracle,sql server,mysql,sqlite 等等所有的关系型的数据库
●SQL语句主要分为:
- ○DQL:数据查询语言,用于对数据进行查询,如select
- ○DML:数据操作语言,对数据进行增加、修改、删除,如insert、udpate、delete
- ○TPL:事务处理语言,对事务进行处理,包括begin transaction、commit、rollback
- ○DCL:数据控制语言,进行授权与权限回收,如grant、revoke
- ○DDL:数据定义语言,进行数据库、表的管理等,如create、drop
- ○CCL:指针控制语言,通过控制指针完成表的操作,如declare cursor
●对于web程序员来讲,重点是数据的crud(增删改查),必须熟练编写DQL、DML,能够编写DDL完成数据库、表的操作,其它语言如TPL、DCL、CCL了解即可
●SQL 是一门特殊的语言,专门用来操作关系数据库
●不区分大小写
MySQL
简介
MySQL是一个关系型数据库管理系统,由瑞典MySQL AB公司开发,后来被Sun公司收购,Sun公司后来又被Oracle公司收购,目前属于Oracle旗下产品
特点
- 使用C和C++编写,并使用了多种编译器进行测试,保证源代码的可移植性
- 支持多种操作系统,如Linux、Windows、AIX、FreeBSD、HP-UX、MacOS、NovellNetware、OpenBSD、OS/2 Wrap、Solaris等
- 为多种编程语言提供了API,如C、C++、Python、Java、Perl、PHP、Eiffel、Ruby等
- 支持多线程,充分利用CPU资源
- 优化的SQL查询算法,有效地提高查询速度
- 提供多语言支持,常见的编码如GB2312、BIG5、UTF8
- 提供TCP/IP、ODBC和JDBC等多种数据库连接途径
- 提供用于管理、检查、优化数据库操作的管理工具
- 大型的数据库。可以处理拥有上千万条记录的大型数据库
- 支持多种存储引擎
- MySQL 软件采用了双授权政策,它分为社区版和商业版,由于其体积小、速度快、总体拥有成本低,尤其是开放源码这一特点,一般中小型网站的开发都选择MySQL作为网站数据库
- MySQL使用标准的SQL数据语言形式
- Mysql是可以定制的,采用了GPL协议,你可以修改源码来开发自己的Mysql系统
- 在线DDL更改功能
- 复制全局事务标识
- 复制无崩溃从机
- 复制多线程从机
mysql语句
show create table table_name --查看表的创建语句
user database_name --切换数据库
desc table_name --查询数据库结构
alter table table_name add col_name col_type --添加字段
alter table table_name modify col_name col_type --修改字段类型
alter table table_name change old_col new_col col_type default '' --修改列明以及默认约束
alter table table_name drop col_name --删除字段
group_concat(col,str....)用法:可以连接组内指定字段的所有取值
limit用法(limit不支持运算,且只能放到最后面)
- limit 0,5,从第0+1条数据开始,往后取5条数据。
- limit 0,2 每页显示2个,展示第一个页面
- limit 2,2 每页显示2个,展示第二个页面
左右内连接
自关联
左右内连接的两张表是同一张表。
外键
会造成数据库查询瓶颈,数据特别慢,设置一个中间表,然后声明两张表的关系。然后借助关系表去跨表查询。
NoSQL
NoSQL:一类新出现的数据库(not only sql)
泛指非关系型的数据库
- ●不支持SQL语法
- ●存储结构跟传统关系型数据库中的那种关系表完全不同,nosql中存储的数据都是KV形式
- ●NoSQL的世界中没有一种通用的语言,每种nosql数据库都有自己的api和语法,以及擅长的业务场景
- ●NoSQL中的产品种类相当多:
- ○Redis
- ○Mongodb
- ○Hbase hadoop
- ○Cassandra hadoop
NoSQL和SQL数据库的比较:
- 适用场景不同:sql数据库适合用于关系特别复杂的数据查询场景,nosql反之
- 事务 特性的支持:sql对事务的支持非常完善,而nosql基本不支持事务
- 两者在不断地取长补短,呈现融合趋势
Redis
编辑redis指令时可以通过前几个字母+Tab进行补全
- Redis是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。从2010年3月15日起,Redis的开发工作由VMware主持。从2013年5月开始,Redis的开发由Pivotal赞助。
- Redis是 NoSQL技术阵营中的一员,它通过多种键值数据类型来适应不同场景下的存储需求,借助一些高层级的接口使用其可以胜任,如缓存、队列系统的不同角色
Redis特性
- Redis 与其他 key - value 缓存产品有以下三个特点:
- Redis支持数据的持久化,可以将内存中的数据保存在磁盘中,重启的时候可以再次加载进行使用。
- Redis不仅仅支持简单的key-value类型的数据,同时还提供list,set,zset,hash等数据结构的存储。
- Redis支持数据的备份,即master-slave模式的数据备份。
Redis 优势
- 性能极高 – Redis能读的速度是110000次/s,写的速度是81000次/s 。
- 丰富的数据类型 – Redis支持二进制案例的 Strings, Lists, Hashes, Sets 及 Ordered Sets 数据类型操作。
- 原子 – Redis的所有操作都是原子性的。
- 丰富的特性 – Redis还支持 publish/subscribe, 通知, key 过期等等特性。
Redis应用场景
- 用来做缓存(ehcache/memcached)——redis的所有数据是放在内存中的(内存数据库)
- 可以在某些特定应用场景下替代传统数据库——比如社交类的应用
- 在一些大型系统中,巧妙地实现一些特定的功能:session共享、购物车
- 只要你有丰富的想象力,redis可以用在可以给你无限的惊喜…….
redis中文官网 (所有命令在里面都有)
Redis与Mysql使用场景
mysql
redis
redis安装
window安装参考:Redis 在windows系统的安装_y小恒的博客-CSDN博客_redis windows版使用安装
安装:sudo apt install redis-server
配置:sudo vim /etc/redis/redis.conf
默认只允许本地访问,将其bind 127.0.0.1注释掉即可,此时可以远程访问。
这里默认是no,将其改成yes,表示可以在后台运行
重启redis:sudo service redis-server restart
Redis客户端和服务端
redis架构同mysql,终端命令行即客户端,通过命令与socket协议与服务端连接,即C/S架构。
- 服务器端的命令为redis-server
- 可以使⽤help查看帮助⽂档redis-server --help
- 个人习惯
- ps aux | grep redis 查看redis服务器进程
- sudo kill -9 pid 杀死redis服务器
- sudo redis-server /etc/redis/redis.conf 指定加载的配置文件
客户端
- 客户端的命令为redis-cli
- 可以使⽤help查看帮助⽂档
- redis-cli --help
- 连接redis
- redis-cli
运⾏测试命令 ping 出现pong表示正常
- 切换数据库
- 数据库没有名称,默认有16个,通过0-15来标识,连接redis默认选择第一个数据库
- select 10
redis中类似于navicat的数据库可视化管理工具:RESP.app
Redis数据操作
数据结构
- redis是key-value的数据结构,每条数据都是⼀个键值对
- 键的类型是字符串
- 注意:键不能重复
值的类型分为五种:
- 字符串string
- 哈希hash
- 列表list
- 集合set
- 有序集合zset
String
字符串类型是 Redis 中最为基础的数据存储类型,它在 Redis 中是二进制安全的,这便意味着该类型可以接受任何格式的数据,如JPEG图像数据或Json对象描述信息等。在Redis中字符串类型的Value最多可以容纳的数据长度是512M。
如果设置的键不存在则为添加,如果设置的键已经存在则修改
set设置,get获取
设置键为name值为tuling的数据
set name tuling
设置键值及过期时间,以秒为单位
setex key seconds value
设置键为aa值为aa过期时间为3秒的数据
setex aa 3 aa # 表示设置键为aa其值为aa的数据有效期为3秒
超时后这个键个值会一起删除
设置多个键值
mset key1 value1 key2 value2 ...
设置键为a1值为python、键为a2值为java、键为a3值为c
mset a1 python a2 java a3 c
根据键获取值,如果不存在此键则返回nil
get key
根据多个键获取多个值
mget key1 key2 ...
获取键a1、a2、a3的值
mget a1 a2 a3
获取库中所有键
keys *
键命令
查找键,参数⽀持正则表达式
keys pattern
查看所有键
keys *
查看名称中以a开头的键
keys a*
判断键是否存在,如果存在返回1,不存在返回0
exists key1
查看键对应的value的类型(为redis支持的五种类型之一)
type key
删除键及对应的值
del key1 key2 ...
设置过期时间,以秒为单位(如果没有指定过期时间则⼀直存在,直到使⽤DEL移除)
expire key seconds
设置键a1的过期时间为3秒
expire a1 3
查看有效时间,以秒为单位
ttl key
hash
- hash⽤于存储对象,对象的结构为属性、值
- 值的类型为string
设置单个属性
hset key field value
设置键 user的属性name为tuling
hset user name tuling
设置多个属性
hmset key field1 value1 field2 value2 ...
设置键u2的属性name为python、属性age为11
hmset u2 name python age 11
获取指定键所有的属性
hkeys key
获取键u2的所有属性
hkeys u2
获取⼀个属性的值
hget key field
获取键u2属性name的值
hget u2 name
获取多个属性的值
hmget key field1 field2 ...
获取所有属性的值
hvals key
删除整个hash键及值,使⽤del命令
删除属性,属性对应的值会被⼀起删除
hdel key field1 field2 ...
删除键u2的属性age
hdel u2 age
list
- 列表的元素类型为string
- 按照插⼊顺序排序
在左侧插⼊数据
lpush key value1 value2 ...
从键为a1的列表左侧加⼊数据a 、 b 、c,得到的列表为[c,b,a]
lpush a1 a b c
在右侧插⼊数据
rpush key value1 value2 ...
从键为a1的列表右侧加⼊数据0、1,得到的列表为[0,1]
rpush a1 0 1
返回列表⾥指定范围内的元素
start、stop为元素的下标索引
索引从左侧开始,第⼀个元素为0
索引可以是负数,表示从尾部开始计数,如-1表示最后⼀个元素
lrange key start stop
获取键为a1的列表所有元素
lrange a1 0 -1
删除指定元素
将列表中前count次出现的值为value的元素移除
count >0: 从头往尾移除
count < 0: 从尾往头移除
count = 0: 移除所有
lrem key count value
向列表a2中加⼊元素a、b、a、b、a、b,得到[b,a,b,a,b,a]
lpush a2 a b a b a b
从a2列表右侧开始删除2个b,剩余[b,a,a,a]
lrem a2 -2 b
set
- ⽆序集合
- 元素为string类型
- 元素具有唯⼀性,不重复
- 说明:对于集合没有修改操作
添加元素
sadd key member1 member2 ...
向键a3的集合中添加元素zhangsan、lisi、wangwu
sadd a3 zhangsan sili wangwu
返回所有的元素
smembers key
获取键a3的集合中所有元素
smembers a3
删除指定元素
srem key
删除键a3的集合中元素wangwu
srem a3 wangwu
zset
- sorted set,有序集合
- 元素为string类型
- 元素具有唯⼀性,不重复
- 每个元素都会关联⼀个double类型的score,表示权重,通过权重将元素从⼩到⼤排序
- 说明:没有修改操作
添加
zadd key score1 member1 score2 member2 ...
向键a4的集合中添加元素lisi、wangwu、zhaoliu、zhangsan,权重分别为4、5、6、3
zadd a4 4 lisi 5 wangwu 6 zhaoliu 3 zhangsan
返回指定范围内的元素
start、stop为元素的下标索引
索引从左侧开始,第⼀个元素为0
索引可以是负数,表示从尾部开始计数,如-1表示最后⼀个元素
zrange key start stop
获取键a4的集合中所有元素
zrange a4 0 -1
删除指定元素
zrem key member1 member2 ...
删除集合a4中元素zhangsan
zrem a4 zhangsan
python操作redis
安装Redis的有3种方式https://github.com/andymccurdy/redis-py
- 第一种:进⼊虚拟环境,联⽹安装包redis
- pip install redis
- 第二种:进⼊虚拟环境,联⽹安装包redis
- easy_install redis
- 第三种:到中⽂官⽹-客户端下载redis包的源码,使⽤源码安装
- wget https://github.com/andymccurdy/redis-py/archive/master.zip
- unzip master.zip
- cd redis-py-master
- sudo python setup.py install
调用模块
- 引⼊模块from redis import Redis
- 这个模块中提供了Redis对象,⽤于连接redis服务器,并按照不同类型提供 了不同⽅法,进⾏交互操作
创建对象
通过init创建对象,指定参数host、port与指定的服务器和端⼝连接,host默认为localhost,port默认为6379,db默认为0
from redis import Redis
sr = Redis(host='localhost', port=6379, db=0)
# 简写
sr = Redis()
根据不同的类型,拥有不同的实例⽅法可以调⽤,与前⾯学的redis命令对应,⽅法需要的参数与命令的参数⼀致
string
set、setex、mset、append、get、mget、key
keys
exists、type、delete、expire、getrange、ttl
hash
hset、hmset、hkeys、hget、hmget、hvals、hdel
list
lpush、rpush、linsert、lrange、lset、lrem
set
sadd、smembers、srem
zset
zadd、zrange、zrangebyscore、zscore、zrem、zremrangebyscore
string操作
from redis import Redis
sr = Redis()
# 创建Redis对象,与redis服务器建⽴连接
sr = Redis()
#⽅法set,添加键、值,如果添加成功则返回True,如果添加失败则返回False
# 添加键name,值为tuling
result = sr.set('name','tuling')
⽅法get,添加键对应的值,如果键存在则返回对应的值,如果键不存在则返回None
result = sr.get('name') # 返回字节需要用decode解码
⽅法set,如果键已经存在则进⾏修改,如果键不存在则进⾏添加
result = sr.set('name','python') #操作成功则返回True,否则返回False
⽅法delete,删除键及对应的值,如果删除成功则返回受影响的键数,否则则返 回0
result = sr.delete('name') #删除成功则返回受影响的键数,否则则返回0
⽅法keys,根据正则表达式获取键
result = sr.keys() #所有的键构成⼀个列表,如果没有键则返回空列表
如果连接失败需要将配置文件中的protected-mode 改为no
MongoDB
nosql 与 Mongodb的简单介绍
- ●“NoSQL”⼀词最早于1998年被⽤于⼀个轻量级的关系数据库的名字
- ●随着web2.0的快速发展, NoSQL概念在2009年被提了出来
- ●NoSQL在2010年⻛⽣⽔起, 现在国内外众多⼤⼩⽹站, 如facebook、 google、 淘宝、 京东、 百度等, 都在使⽤nosql开发⾼性能的产品
- ●对于⼀名程序员来讲, 使⽤nosql已经成为⼀条必备技能
- ●NoSQL最常⻅的解释是“non-relational”, “Not Only SQL”也被很多⼈接受, 指的是⾮关系型的数据库
mongodb的优势
- 易扩展: NoSQL数据库种类繁多, 但是⼀个共同的特点都是去掉关系数据库的关系型特性。 数据之间⽆关系, 这样就⾮常容易扩展
- ⼤数据量, ⾼性能: NoSQL数据库都具有⾮常⾼的读写性能, 尤其在⼤数据量下, 同样表现优秀。 这得益于它的⽆关系性, 数据库的结构简单
- 灵活的数据模型: NoSQL⽆需事先为要存储的数据建⽴字段, 随时可以存储⾃定义的数据格式。 ⽽在关系数据库⾥, 增删字段是⼀件⾮常麻烦的事情。 如果是⾮常⼤数据量的表, 增加字段简直就是⼀个噩梦
mongo没有数据库概念,而通过集合collections(可以理解为sql中的table)存储数据,集合中的每一个元素类似于python中的dict,可以理解为table中的每一行。
mongodb支持navicat
MongoDB 安装配置
ubuntu示例
apt安装
sudo apt install mongod
配置mongodb远程连接
sudo vim /etc/mongodb.conf
将下面这个注释,或改成0.0.0.0
# bind_ip 127.0.0.1
服务端启动
sudo service mongodb restart
客户端
# 启动本地客户端
mongo
# 查看帮助
mongo --help
# 退出
exit
window安装
可以参考Windows下安装 MongoDB_Dragon-v的博客-CSDN博客_windows安装mongodb
我这里安装的是5.0.9的 跟参考文章版本不一样,似乎已经自己创建了data和log文件夹,并且自己还设置了服务名和密码,我设置成123456
如果在启动配置文件时报错:[SC] CreateService 失败 1073:
参考:[SC] CreateService 失败 1073: 指定的服务已存在。_冷凝娇的博客-CSDN博客_指定的服务已存在 这里有个地方作者没有提到,当我们sc delete MongoDB服务名删除后,如果sc.exe create重启成功后需要在服务中启动MongoDB。
设置开机自启
mongod.exe --logpath C:\works\software\mongodbs\log\mongodb.log --logappend -- dbpath C:\works\software\mongodbs\data --directoryperdb --serviceName MongoDB -- install
相应的路径改成自己的即可
关于database的基础命令
查看当前数据库: db
查看所有的数据库: show dbs / show databases
切换数据库: use db_name
删除当前数据库: db.DropDatabase()
在mongodb数据库中, 没有新建数据库的指令,可以直接use需要新建的数据库,mongo会自动创建。
# 当前mongo不存在test1 但是照样可以切换
use test1
# 注意点:在数据库没有数据时,数据库并不会真正创建 当插入数据时,就可以使用show dbs查看到test1了
显示的是所有容器名以及占用内存,容器也可以理解成数据库
关于集合的基础命令
# 自动创建集合
# 向不存在的集合中第一次加入数据时,集合会被创建出来
# 手动创建集合 语法,set_name为集合名称
db.createCollection(set_name, options)
db.createCollection("stu")
db.createCollection("sub", {capped: true, size: 10})
# 参数capped: 默认值为false表示不设置上限,值为true表示设置上限
# 参数size: 当capped值为true时,需要指定此参数,表示上限大小。
# 当文档达到上限时,会将之前的数据覆盖,单位为字节。(使用先进先出原则,当超过上限时,先插入集合的数据被覆盖)
# 查看集合
show collections
# 删除集合,删完后如果数据库为空,show dbs就看不到db了
db.集合名称.drop()
删除失败返回false,成功返回true
字符串用单引号和双引号都可以,且大小写敏感。
数据类型
文档可以理解为对象。
Object ID:文档ID
String:字符串 该属性是最常用的数据类型,并且为一个有效的UTF-8字符集
Boolean:存储一个布尔值,true或者false
Integer:整数 可以是32位或64位,取决于服务器
Double:浮点值
Arrays:数组或列表,多个值存储到一个键
Object:用于嵌入式的文档,即一个值为一个文档
Null:Null值
Timestamp: 时间戳 表示1970-1-1到现在的总秒数
Date:存储当前日期或时间的UNIX时间格式
创建日期语句如下:
# 参数的格式为YYYY-MM-DD 查看当前时间
new Date('2017-12-20')
# 查看当前时间
Date()
每个文档都有自己的属性,为_id。保证每个文档的唯一性
可以自己去设置_id插入文档,如果没有提供,那么mongodb为每个文档提供一个独特的_id,类型为object ID
object ID是一个12字节的十六进制数:
- ●前4个字节为当前时间戳
- ●接下来3个字节为机器ID
- ●后2个字节为MongoDB的服务进程ID
- ●最后3个字节是简单的增量值
可以自定义object id
数据操作
数据插入
db.集合名称.insert(docment)
# 例如
db.stu.insert({"name": "xiaoming", "age": 10})
# 查询当前集合数据 并返回_id
db.stu.find()
# 在终端中插入的数据为json 并且数据中的键可以省略双引号
db.stu.insert({name: "xiaohong", age: 18})
db.stu.find()
数据保存
db.集合名称.save(document)
# 如果文档的_id已经存在则修改,如果文档的_id不存在则添加数据
db.stu.insert({_id: 10010, name: "xiaoming", age: 30})
# 尝试插入数据 如果当前_id相同,则报错[当前id值重复]
db.stu.insert({_id: 10010, name: "xiaoming", age: 40})
# 调用save保存则更新数据
db.stu.save({_id: 10010, name: "xiaoming", age: 40})
save与insert的区别:insert如果_id已存在则报错,save则是覆盖(先删了原来的再插入)
数据更新
db.集合名称.update(<query>, <update>, {multi: <boolean>})
# query: 查询条件
# update: 更新操作符
# multi: 可选参数,默认为false。
# 表示只更新找到的第一条记录,值为true则更新满足条件的全部数据
# 当前这条语句会替换之前的记录,则原数据中的age会消失
db.stu.update({name: "xiaowang"}, {name: "xiaozhao"})
# 为了不影响除了name之外的其他数据 需要使用$set语法
db.stu.update({name: "xiaowang"}, {$set: {name: "xiaozhao"}})
# 更新所有符合条件的数据 multi参数必须和$符配合使用
db.stu.update({name: "xiaowang"}, {$set: {name: "xiaozhao"}}, {multi: true})
数据删除
db.集合名称.remove(<query>, {justOne: <boolean>})
# query: 删除指定文档的条件
# justOne: 可选参数,如果设置为true或1,删除一条。默认false,表示删除多条
# 删除符合条件的全部数据
db.stu.remove({name: "xiaozhao"})
# 删除一条
db.stu.remove({name: "xiaozhao"}, {justOne: true})
数据查询
# 普通查询: find()
db.集合名称.find({条件文档})
db.stu_1.find({age:20}) # 查询age=20的数据
# 查询一个: findOne(),查第一条
db.集合名称.findOne({条件文档})
db.stu_1.findOne({age:18})
# pretty(): 将结果格式化
db.集合名称.find({条件文档}).pretty()
db.stu_1.find().pretty()
比较运算符
- 等于:默认是等于判断,没有运算符
- 小于:$lt
- 小于等于:$lte
- 大于:$gt
- 大于等于:$gte
- 不等于:$ne
db.stu_1.find({age: {$gte: 18}}) # 查询age>=18的数据
范围运算符
# 使用"$in"进行返回查询 符合18或28的返回
db.stu_1.find({age: {$in: [18, 28]}}) # 查询age=18或28的数据
逻辑运算法
# 并且查询
db.stu_1.find({age: 18, hometown: "桃花岛"})
# 或者查询
db.集合名称.find({$or: [{查询条件}, {查询条件}]})
db.stu_1.find({$or: [{age: 18}, {hometown: "桃花岛"}]})
# 将之前所学的查询进行整合使用
db.stu_1.find({$or: [{age: {$gte: 45}}, {hometown: {$in:["桃花岛", "华山"]}}]})
# 如果语句过长,可以使用编辑器写上查询语句 并且换行不影响
正则表达式
# 使用//或$regex编写正则表达式
db.products.find({sku:/^abc/})
db.products.find({sku: {$regex: "789$"}}) # 以789结尾的数据
limit与skip
# ⽅法limit(): ⽤于读取指定数量的⽂档
db.集合名称.find().limit(NUMBER)
# 查询两条信息
db.products.find().limit(2)
# 查询除了前两条之外的所有记录
db.products.find().skip(2)
# 组合使用,前两条之外的前两条,也就是第3-4条
db.products.find().skip(2).limit(2)
自定义查询
# 使⽤$where后⾯写⼀个函数, 返回满⾜条件的数据
# 查询年龄⼤于30的学⽣
db.stu_1.find({$where: function(){return this.age<=18}})
投影
# 在查询到的返回结果中,只选择必要的字段
# 如果不想显示_id,需要单独设置_id: 0
db.集合名称.find({条件}, {字段名称1, 字段名称2...})
# 这里查age大于18,且只显示name子弹
db.stu_1.find({age: {$gt: 18}}, {name: 1, _id: 0})
# 无条件进行投影查询
db.stu_1.find({}, {name: 1, _id: 0})
排序
# 方法sort() 用于对集合进行排序
db.集合名称.find().sort({字段: 1})
# 1为升序 -1为降序
db.stu_1.find().sort({age: -1})
# 多条件排序
db.stu_1.find().sort({age: -1, gender: -1})
# 筛选年龄大于18并使用age升序进行排序
db.stu_1.find({age: {$gt: 18}}).sort({age: 1})
记录统计
# 统计学生个数
db.stu_1.find().count()
# 统计年龄大于18的学生个数
db.stu_1.find({age: {$gt: 18}}).count()
# 第二种写法
db.stu_1.count()
db.stu_1.count({age: {$gt: 18}})
数据去重
# 对地址进行去重,返回list
db.stu_1.distinct("hometown")
# 结合条件查询去重,查询age>20的hometowm并且去重
db.stu_1.distinct("hometown", {age: {$gt: 20}})
数据备份与恢复
备份语法
mongodump -h dbhost -d dbname -o dbdirectory
-h: 服务器地址, 也可以指定端⼝号
-d: 需要备份的数据库名称
-o: 备份的数据存放位置, 此⽬录中存放着备份出来的数据
mongodump -h 192.168.196.128:27017 -d test1 -o ~/Desktop/test1bak
# 本地备份示例
mongodump -d test1 -o ~/Desktop/code
恢复语法
mongorestore -h dbhost -d dbname --dir dbdirectory
-h: 服务器地址
-d: 需要恢复的数据库实例
--dir: 备份数据所在位置
mongorestore -h 192.168.196.128:27017 -d test2 --dir ~/Desktop/test1bak/test1
# 本地恢复
mongorestore -d test1 --dir ~/Desktop/code/test
聚合操作
聚合(aggregate)是基于数据处理的聚合管道,每个文档通过一个由多个阶段(stage)组成的管道,可以对每个阶段的管道进行分组、过滤等功能,然后经过一系列的处理,输出相应的结果。
db.集合名称.aggregate({管道:{表达式}})
常用管道
$group:
将集合中的⽂档分组, 可⽤于统计结果
$match:
过滤数据, 只输出符合条件的⽂档
$project:
修改输⼊⽂档的结构, 如重命名、 增加、 删除字段、 创建计算结果
$sort:
将输⼊⽂档排序后输出
$limit:
限制聚合管道返回的⽂档数
$skip:
跳过指定数量的⽂档, 并返回余下的⽂档
$unwind:
将数组类型的字段进⾏拆分
表达式
$sum:
计算总和, $sum:1 表示以⼀倍计数
$avg:
计算平均值
$min:
获取最⼩值
$max:
获取最⼤值
$push:
在结果⽂档中插⼊值到⼀个数组中
$first:
根据资源⽂档的排序获取第⼀个⽂档数据
$last:
根据资源⽂档的排序获取最后⼀个⽂档数据
$group
- 将集合中的文档分组,可用于统计结果
- _id表示分组的依据,使用某个字段的格式为"$字段"
- 案例:统计男生、女生的总人数
# $sum: 1 可以理解成统计文档中分组之后的每一条数据的结果 * 1
db.stu_1.aggregate(
{
$group: {_id: "$gender", counter: {$sum: 1}}
}
)
# id表示基于gender分组,counter即人数统计,最后会显示两个字段,_id和counter
# $sum表示求和函数
案例:按照gender分组,获取不同组数据的个数和平均年龄
db.stu_1.aggregate(
{
$group: {_id: "$gender", count: {$sum: 1}, avg_age: {$avg: "$age"}}
}
)
# $avg表示一个平均数函数
group by null
将集合中所有的文档分为一组
案例:求学生总人数、平均年龄
db.stu_1.aggregate(
{
$group: {_id: null, counter: {$sum: 1}, avg_age: {$avg: "$age"}}
}
)
group的注意点
- $group 对应的字典中有几个键,结果中就有几个键
- 分组依据需要放在_id后面
- 取不同的字段需要在字段前加$,例如:$gender、$age
$project
修改文档的结构。如:重命名、增加字段、删除字段、创建计算结果
案例:查询学生的姓名、年龄
# 类似于投影
db.stu_1.aggregate(
{
$project: {_id: 0, name: 1, age: 1}
}
)
案例:查询性别数据、人数统计、平均年龄,并以中文显示
db.stu_1.aggregate(
{
$group: {_id: "$gender", count: {$sum: 1}, avg_age: {$avg: "$age"}}
},
{
$project: {"性别": "$_id", "人数统计": "$count", "平均年龄": "$avg_age", _id: 0}
}
)
$match
用于过滤数据,只输出符合条件的文档
match是管道命令,能将结果交给下一个管道,find()无法实现
案例: 查询年龄大于20的男生
db.stu_1.aggregate(
{
$match: {age: {$gt: 20}}
}
)
案例: 查询年龄大于20的男生人数、女生人数,并以中文字段输出
db.stu_1.aggregate(
{
$match: {age: {$gt: 20}},
},
{
$group: {_id: "$gender", counter: {$sum: 1}}
},
{
$project: {"性别": "$_id", "统计人数": "$counter", _id: 0}
}
)
# 拓展:查询年龄大于20或者归属地在蒙古或大理的人数
db.stu_1.aggregate(
{
$match:
{
$or:
[
{
age: {$gt: 20}
},
{
hometown: {$in: ["蒙古", "大理"]}
}
]
},
},
{
$group: {_id: "$gender", counter: {$sum: 1}}
},
{
$project: {"性别": "$_id", "统计人数": "$counter", _id: 0}
}
)
$sort
将输入文档排序后输出
案例:查询学生信息,按年龄升序
db.stu_1.aggregate(
{
$sort: {age: 1}
}
)
案例:查询男生人数、女生人数。按人数降序
db.stu_1.aggregate(
{
$group: {_id: "$gender", counter: {$sum: 1}}
},
{
$sort: {counter: -1}
}
)
$limit与$skip
$limit
限制聚合函数返回的文档数
案例:查询两条学生信息
db.stu_1.aggregate(
{$limit: 2}
)
$skip
跳过指定数量的文档,并返回余下的文档
案例:查询从第三条数据开始的学生信息
db.stu_1.aggregate(
{$skip: 2}
)
案例:统计男生、女生人数。按人数升序并取第二条数据
db.stu_1.aggregate(
{
$group:
{
_id: "$gender", counter: {$sum: 1}
}
},
{
$sort: {counter: 1}
},
{
$skip: 1
},
{
$limit: 1
}
)
索引
索引:用于提升查询速度
插入10万条数据到数据库中
for(i = 0; i < 100000; i++){
db.test_data.insert({name: "test" + i, age: i})
}
# 查询数据
db.test_data.find({name: "test10000"})
# 获取查询数据所花费的时间
db.test_data.find({name: "test10000"}).explain("executionStats")
建立索引
# 语法示例
# 1代表升序 -1代表降序
db.集合名称.ensureIndex({属性: 1})
db.test_data.ensureIndex({name: 1})
db.test_data.find({name: "test10000"}).explain("executionStats")
# 查看索引
db.test_data.getIndexes()
索引使用
默认情况下创建的索引不是唯一索引
创建唯一索引
# 在爬虫项目中可以通过唯一索引进行数据去重
db.test_data.ensureIndex({"name": 1}, {"unique": true})
创建唯一索引并消除重复
db.test_data.ensureIndex({"name": 1}, {"unique": true, "dropDups": true})
建立联合索引
db.test_data.ensureIndex({name: 1, age: 1})
查看当前集合的所有索引
db.test_data.getIndexes()
删除索引
db.test_data.dropIndex({name: 1})
pymongo的操作
安装:pip install pymongo
# 导入模块
from pymongo import MongoClient
# 实例化client建立连接并指定集合 当前mongo演示为本地
client = MongoClient(host='127.0.0.1', port=27017)
# test是数据库,test_python是下面的集合,如果没有这个集合它会自己创建(插入时)
collection = client['test']['test_python']
# 插入一条数据
res = collection.insert_one({"name": "xiaoming", "age": 10})
print(res)
# 插入多条数据
data_list = [{"name": "test{}".format(i)} for i in range(10)]
collection.insert_many(data_list)
# 查询一条数据
t_1 = colltction.find_one({"name": "xiaowang"})
print(t_1)
# 查询所有记录
t_2 = collection.find({"name": "xiaowang"})
# 当前返回的是一个游标对象
print(t_2)
for i in t_2:
print(i)
# 对游标对象进行列表类型转换
print(list(t_2))
# 更新一条数据
collection.update_one({"name": "test1"}, {"$set": {"name": "new_test1"}})
# 更新全部数据
collection.update_many({"name": "test1"}, {"$set": {"name": "new_test1"}})
# 删除一条数据
collection.delete_one({"name": "test10"})
# 删除全部数据
collection.delete_many({"name": "test9"})