一、mongodb的介绍
1、nosql的介绍
- "NoSQL"⼀词最早于1998年被⽤于⼀个轻量级的关系数据库的名字
- 随着web2.0的快速发展, NoSQL概念在2009年被提了出来
- NoSQL在2010年⻛⽣⽔起, 现在国内外众多⼤⼩⽹站, 如facebook、 google、 淘宝、 京东、 百度等, 都在使⽤nosql开发⾼性能的产品
- 对于⼀名程序员来讲, 使⽤nosql已经成为⼀条必备技能
- NoSQL最常⻅的解释是“non-relational”, “Not Only SQL”也被很多⼈接受, 指的是⾮关系型的数据库
2、关系和非关系型的介绍
不管我们学习什么数据库都应该学习其中的基础概念,在mongodb中基本的概念是 <b style='color:red'>文档、集合、数据库</b>
SQL概念 | MongoDB概念 | 说明 |
---|---|---|
database | database | 数据库 |
table | collection | <b>数据库表/集合 |
row | document | <b>数据记录行/文档 |
column | field | 数据字段/域 |
index | index | 索引 |
table joins | 表连接mongoDB不支持 | |
primary key | primary key | 主键,MongoDB自动将_id设置为主键 |
- 通过图示我们也可以更加直观的了解Mongo中的一些概念
关系数据库很强⼤,但是它并不能很好的应付所有的应⽤场景。 MySQL的扩展性差,⼤数据下IO压⼒⼤, 表结构更改困难
3、mongdb的优势
优势 | 说明 |
---|---|
易扩展 | NoSQL数据库种类繁多,但是⼀个共同的特点都是去掉关系数据库的关系型特性.数据之间⽆关系,这样就⾮常容易扩展 |
大数据量,高性能 | NoSQL数据库都具有⾮常⾼的读写性能,尤其在⼤数据量下,同样表现优秀.这得益于它的⽆关系性,数据库的结构简单 |
灵活的数据模型 | NoSQL⽆需事先为要存储的数据建⽴字段,随时可以存储⾃定义的数据格式.⽽在关系数据库⾥,增删字段是⼀件⾮常麻烦的事情.如果是⾮常⼤数据量的表,增加字段简直就是⼀个噩梦 |
二、mongodb安装
sudo apt-get install mongodb
三、mongodb基本命令
1. 常用基本命令
功能 | 命令 |
---|---|
启动 | sudo service mongod start |
停止 | sudo service mongod stop |
重启 | sudo service mongod restart |
查看是否启动成功 | ps ajx | grep mongod |
配置文件的位置 | /etc/mongod.conf |
默认端口 | 27017 |
日志的位置 | /var/log/mongodb/mongod.log |
启动本地客户端 | mongo |
查看帮助 | mongo -help |
退出 | exit或者ctrl+c |
2. 关于数据库的基本命令
功能 | 命令 |
---|---|
查看当前的数据库 默认为test数据库 |
db |
查看所有的数据库 | show dbs 或者 show databases |
切换数据库 如果数据库<b style='color:red'>不存在,则创建,否则切换</b>到指定数据库 |
use db_name |
删除当前的数据库 注意:先切换到要删除的数据库 |
db.dropDatabase() |
3. 关于集合的基础命令
在mangodb里面没有表的概念,集合就相当于表,不手动创建集合,<b style='color:red'>向不存在的集合中第一次加入数据时,集合就会被创建出来</b>
语法 | 说明 | 举例 |
---|---|---|
db.createCollection(name,options) | 手动创建集合 (一般很少使用) |
1. db.createCollection('user') 2.db.createCollection('user2',{capped:true,size:10}) <b style='color:red'>参数capped:</b>默认值为false表示不设置上限,值为true表示设置上限 <b style='color:red'>参数size:</b> 当capped值为true时,需要指定此参数,表示上限大小,<u>当文档达到上限时,会将之前的数据覆盖</u>,单位为字节 |
show collections | 查看集合 | |
db.集合名称.drop() | 删除集合 | db.user2.drop() |
4. 关于mangodb数据类型
类型 | 说明 |
---|---|
Object ID | <b>文档ID</b> 1、 每个文档都有一个属性,为_id,保证每个文档的<b>唯一性</b> 2、 可以自己去设置_id插入文档,如果没有提供,那么MongoDB为每个文档提供了一个独特的_id,类型为objectID 3、 ObjectID是一个<u style='color:blue'>12字节的十六进制数:</u> (1)、 前4个字节为当前<u>时间戳</u> (2)、 接下来的3个字节的<u>机器ID</u> (3)、 接下来的2个字节中<u>MongoDB的服务进程id</u> (4)、 最后3个字节是<u>简单的增量值 |
<b style='color:red'>String</b> | <b>字符串,最常用,必须是有效的UTF-8 |
<b style='color:red'>Boolean</b> | <b>存储一个布尔值,true或false |
Integer | 整数可以是32位或者64位,这取决于服务器 |
Double | 存储浮点值 |
Arrays | 数组或者列表,多个值存储到一个键 |
Object | 用于嵌入式的文档,即一个值为一个文档 |
<b style='color:red'>Null</b> | <b>存储Null值 |
Timestamp | 时间戳,表示从1970-1-1到现在的总秒数 |
Date | <b>存储当前日期或时间的Unix时间格式</b> 创建日期语句如下:参数的格式为YYYY-MM-DD</br> new Date('2018-9-28')</br> |
5. 插入(文档)
语法 | 说明 | 举例 |
---|---|---|
db.COLLECTION_NAME.insert(document) | db.集合名称.insert(文档) 文档的数据结构和JSON基本一样。 所有存储在集合中的数据都是BSON格式。 BSON是一种类json的一种二进制形式的存储格式,简称Binary JSON。 |
1、db.test2.insert({name:'zhangsan',age:18}) 2、db.test2.insert({name:'wangwu',age:20,_id:20180101}) |
6. 更新
6.1、save()
-- 如果文档的_id已经存在则修改,如果文档的_id不存在则添加
db.集合名称.save(document)
6.2、update()
- 语法
db.集合名称.update(
<query>,
<update>,
{
upsert: <boolean>,
multi: <boolean>,
writeConcern: <document>
}
)
- 参数说明:
- query : update的查询条件,类似sql update查询内where后面的。
- update : update的对象和一些更新的操作符(如inc...)等,也可以理解为sql update查询内set后面的
- upsert : 可选,这个参数的意思是,如果不存在update的记录,是否插入objNew,true为插入,默认是false,不插入。
- multi : 可选,mongodb 默认是false,只更新找到的第一条记录,如果这个参数为true,就把按条件查出来多条记录全部更新。
- writeConcern :可选,抛出异常的级别。
- 举例 1
-- 把满足条件的全部内容都替换了,age消失了
db.test2.update({name:'100cxy'},{name:'cxy100'})
-- 把name为zhangsan的值,替换成zhangsan2
db.test2.update({name:'zhangsan'},{$set:{name:'zhangsan2'}})
[图片上传失败...(image-1c1af4-1538921093790)]
- 举例 2
-- 插入多条数据
db.test2.insert({name:'wangwu',age:21})
db.test2.insert({name:'wangwu',age:31})
db.test2.insert({name:'wangwu',age:41})
db.test2.insert({name:'wangwu',age:51})
db.test2.insert({name:'wangwu',age:61})
[图片上传失败...(image-5a7398-1538921093790)]
-- 把name为wangwu的值更新为maliu
db.test2.update({name:'wangwu'},{$set:{name:'maliu'}})
-- 更新多条
db.test2.update({name:'wangwu'},{$set:{name:'maliu'}},{'multi':true})
7. 删除
- 语法
db.集合名称.remove(<query>,{justOne: <boolean>})
- 参数query:可选,删除的⽂档的条件
- 参数justOne:可选, 如果设为true或1, 则只删除⼀条, 默认false, 表示删除多条
- 注意: 默认是删除多条
四、mongodb数据查询
数据准备:
db.wzry.insert({name:'司马懿',type:'法师',age:1,gender:true})
db.wzry.insert({name:'孙悟空',type:'战士',age:2,gender:true})
db.wzry.insert({name:'后羿',type:'射手',age:3,gender:true})
db.wzry.insert({name:'刘邦',type:'坦克',age:4,gender:true})
db.wzry.insert({name:'花木兰',type:'刺客',age:5,gender:false})
db.wzry.insert({name:'太乙真人',type:'辅助',age:5,gender:true})
db.wzry.insert({name:'蔡文姬',type:'辅助',age:6,gender:false})
[图片上传失败...(image-cb6b6a-1538921093790)]
1. 数据查询
方法 | 命令 | 举例 |
---|---|---|
find() | 查询 db.集合名称.find({条件⽂档}) |
db.wzry.find({age:5}) |
findOne() | 查询,只返回第⼀个 db.集合名称.findOne({条件⽂档}) |
db.wzry.findOne({age:5}) |
pretty() | 将结果格式化 db.集合名称.find({条件⽂档}).pretty() |
db.wzry.find({age:5}).pretty() |
[图片上传失败...(image-825f8b-1538921093790)]
2. 比较、范围运算符
功能 | 命令 | 举例 |
---|---|---|
等于 | 默认是等于判断, 没有运算符 | ... |
小于 | $lt (less than) | db.wzry.find({ age : { $lt : 5} } ) |
小于等于 | $lte (less than equal) | db.wzry.find({ age : { $lte : 5} } ) |
大于 | $gt (greater than) | db.wzry.find( { age : { $gt : 2 } }) |
大于等于 | $gte (greater than equal) | ... |
不等于 | $ne (not equal) | ... |
在范围内 | $in | db.wzry.find( {age : { $in : [4,6] } } ) |
不在范围内 | $nin | db.wzry.find( { age : { $nin : [4,6] } } ) |
3、逻辑运算符
逻辑 | 举例 | 说明 |
---|---|---|
逻辑与 and | db.wzry.find({age:5,type:'刺客'}) | 在json中写多个条件即可 |
逻辑或 or | db.wzry.find({$or:[{age:5},{type:'刺客'}]}) | 使用$or ,值为数组,数组中每个元素为json |
4、支持正则表达式
- 使用//或者$regex
-- 以'后'字开头
-- 第一种
db.wzry.find({name:/^后/})
-- 第二种
db.wzry.find({name:{$regex:'^后'}})
5、limit和skip
方法 | 说明 | 举例 |
---|---|---|
limit() | 用于读取指定数量的文档 | db.wzry.find().limit(2) |
skip() | 用于跳过指定数量的文档 | db.wzry.find().skip(2) |
6、自定义查询
- 使⽤$where后⾯写⼀个函数, 返回满⾜条件的数据
<!-- 查询年龄大于5的人物 -->
db.wzry.find({
$where:function(){
return this.age>5;
}
})
7、投影
<b style='color:red'>在查询到的返回结果中, 只选择必要的字段</b>
- 语法
- db.集合名称.find({},{字段名称:1,...})
- 参数为字段与值, 值为1表示显示, 值为0不显
- 特殊: 对于_id列默认是显示的, 如果不显示需要明确设置为0
- 举例
db.wzry.find({},{_id:0,name:1,gender:1})
[图片上传失败...(image-c2e3ad-1538921093790)]
8、排序
- ⽅法sort(), ⽤于对结果集进⾏排序
- db.集合名称.find().sort({字段:1,...})
- 参数1为升序排列
- 参数-1为降序排列
-- 按照age升序排序
db.wzry.find().sort({age:1})
[图片上传失败...(image-7cd3ba-1538921093790)]
9.统计个数
方法:count() ⽤于统计结果集中⽂档条数
- db.集合名称.find({条件}).count()
- db.集合名称.count({条件})
举例
-- 统计年龄大于等于5的人物
db.wzry.find({age:{$gte:5}}).count()
db.wzry.count({age:{$gte:5}})
10.消除重复
方法:distinct() 对数据进行去重
- db.集合名称.distinct('去重字段',{条件})
举例
-- 查看所有职业种类
db.wzry.distinct('type')
五、mongodb聚合(管道与表达式)
MongoDB中聚合(aggregate)主要用于处理数据(诸如统计平均值,求和等),并返回计算后的数据结果。有点类似sql语句中的 count(*)。
1、aggregate() 方法
语法:
db.COLLECTION_NAME.aggregate(AGGREGATE_OPERATION)
聚合的常用表达式:
语法 | 说明 |
---|---|
$sum | 计算总和, $sum:1 表示以⼀倍计数 |
$avg | 计算平均值 |
$min | 获取最⼩值 |
$max | 获取最⼤值 |
$push | 在结果⽂档中插⼊值到⼀个数组中 |
$first | 根据资源⽂档的排序获取第⼀个⽂档数据 |
$last | 根据资源⽂档的排序获取最后⼀个⽂档数据 |
2、管道的概念
管道在Unix和Linux中一般用于将当前命令的输出结果作为下一个命令的参数。
MongoDB的聚合管道将MongoDB文档在一个管道处理完毕后将结果传递给下一个管道处理。管道操作是可以重复的。
表达式:处理输入文档并输出。表达式是无状态的,只能用于计算当前聚合管道的文档,不能处理其它的文档。
常用操作:
语法 | 说明 |
---|---|
$group | 将集合中的⽂档分组, 可⽤于统计结果 |
$match | 过滤数据, 只输出符合条件的⽂档 |
$project | 修改输⼊⽂档的结构, 如重命名、 增加、 删除字段、 创建计算结果 |
$sort | 将输⼊⽂档排序后输出 |
$limit | 限制聚合管道返回的⽂档数 |
$skip | 跳过指定数量的⽂档, 并返回余下的⽂档 |
$unwind | 将数组类型的字段进⾏拆分 |
3、举例
3.1、$group 分组统计
- 按性别分组,并计算男女人数
db.wzry.aggregate([
{
$group:{
_id:'$gender',
num:{
$sum:1
}
}
}
])
说明:
- _id:"gender"表示按照gender属性分组;
- $sum表示求和,如果是$sum:1就相当于count(*),一行记录算一个
- 按性别分组,计算年龄和:
db.wzry.aggregate([
{
$group:{
_id:'gender',
num:{$sum:'age'}
}
}
])
- 按照性别分组,并拿到每个组的第一个年龄:
db.wzry.aggregate([
{
$group:{
_id:"$gender",
num:{
$first:'$age'
}
}
}
])
- 先按性别分组,分组之后将age属性映射到数据中:(相当于分组之后查看同组的数据,MySQL不能实现)
db.wzry.aggregate([
{$group:{
_id:'$gender',
num:{$push:'$age'}
}}
])
[图片上传失败...(image-11a205-1538921093790)]
3.2 $match管道: 类似find,只是find不能统计,现在是可以过滤并统计
- 查询年龄大于3且小于等于5的(只是过滤)
db.wzry.aggregate([
{
$match:{
age:{$gt:3,$lte:5}
}
}
])
- 在上面过滤的基础上再集合(先过滤,再分组)
db.wzry.aggregate([
{
$match:{
age:{$gt:3,$lte:5}
},
},
{
$group:{
_id:"$gender",
num:{
$num:1
}
}
}
])
3.3 $project 修改输入文档的结构.可以用来重命名、增加或删除域,也可以用于创建计算结果以及嵌套文档,类似于find方法的第二个参数
- 查询年龄大于3或者小于等于5,按照性别分组并且统计人数,并且只取人数列
db.wzry.aggregate([
{
$match:{
age:{$gt:3,$lte:5}
}
},
{
$group:{
_id:'$gender',
num:{
$sum:1
}
}
},
{
$project:{
_id:0,
num:1
}
}
])
说明: $project:{_id:0,num:1}表示在结果中取num列,不取_id列
六、索引和备份
6.1、 数据的备份
6.1.1、备份的语法
mongoddump -h dbhost -d dbname -o dbdirectory
6.1.2、参数说明
- -h:服务器地址,也可以指定端口号
- -d:需要备份的数据库名称
- -o:备份的数据存放位置,此目录中存放着备份出来的数据
6.1.3、举例
mongoddump -h 127.0.0.1:27017 -d wzry -o ~/桌面/wzrybak
6.2、数据的恢复
6.2.1、恢复语法
- 恢复语法
mongorestore -h dbhost -d dbname --dir dbdirectory
6.2.2、参数说明
- h: 服务器地址
- d: 需要恢复的数据库实例
--dir: 备份数据所在位置
6.2.3、举例
mongorestore -h 127.0.0.1:27017 -d wzry --dir ~/桌面/wzrybak/wzry
七、mongo和python交互
1、Pymongo
PyMongo是Mongodb的Python接口开发包,是使用python和Mongodb的推荐方式
2、安装
sudo pip install pymongo
3、使用
1、导入模块
import pymongo
# 或者
from pymongo import MongoClient
2、建立与MongoClient的连接
client = MongoClient('localhost',27017)
# 或者
client = MongoClient('mongodb://localhost:27017/')
3、得到数据库
db = client.数据库名
# 或者
db = client['数据库名']
4、得到一个数据集合
collection = db.集合名称
# 或者
collection = db['集合名称']
5、主要方法
- insert_one:加入一条文档对象
- insert_many:加入多条文档对象
- find_one:查找一条文档对象
- find:查找多条文档对象
- update_one:更新一条文档对象
- update_many:更新多条文档对象
- delete_one:删除一条文档对象
- delete_many:删除多条文档对象
6、插入方法
- insert_one() 传入一个字典,表示插入一个文档
- insert_many() 传入一个列表,列表的元素为字典,插入多条文档
from pymongo import *
'''
插入方法:
insert_one() 传入一个字典,表示插入一个文档
insert_many() 传入一个列表,列表的元素为字典,插入多条文档
'''
def insert():
try:
# 1 创建连接对象
client = MongoClient(host="localhost", port=27017)
# 2 获取数据库,
# 如果这个数据库不存在,就在内存中虚拟创建
# 当在库里创建集合的时候,就会在物理真实创建这个数据库
db = client.demo # 使用demo数据库
# 向stu集合插入数据
# 插入一条
db.stu.insert_one({"name": "zs", "age": 20})
# 插入多条
db.stu.insert_many([{"name": 1}, {"name": 2}])
except Exception as e:
print(e)
if __name__ == '__main__':
insert()
7、查询方法
- find_one()返回满足条件的文档集中第一条数据,类型为字典,如果没有查询结果返回None
- 方法find()返回满足条件的所有文档,类型为Cursor对象,可以使用for...in遍历,每项为字典对象,如果没有查询结果返一个空的Cursor对象
from pymongo import *
'''
查询方法:
find_one()返回满足条件的文档集中第一条数据,类型为字典
如果没有查询结果返回None
方法find()返回满足条件的所有文档,类型为Cursor对象,可以使用for...in遍历,每项为字典对象
如果没有查询结果返一个空的Cursor对象
'''
def select():
try:
# 1 创建连接对象
client = MongoClient(host="localhost", port=27017)
# 2 获取数据库,
# 如果这个数据库不存在,就在内存中虚拟创建
# 当在库里创建集合的时候,就会在物理真实创建这个数据库
db = client.demo # 使用demo数据库
# 从stu查询数据
# 查询一条,返回一个字典,如果没有结果返回None
res = db.stu.find_one({"age": 18})
print(res)
# 查询全部结果,返回一个Cursor可迭代对象,每一个元素是字典
# 如果没有查询结果会返回一个空的Cursor对象
res = db.stu.find({"age": {"$gt": 18}})
print(res)
except Exception as e:
print(e)
if __name__ == '__main__':
select()
8、修改方法
- update_one()修改满足条件的文档集中的第一条文档
- update_many()修改满足条件的文档集中的所有文档
- 注意:使用$set操作符修改特定属性的值,否则会修改整个文档
from pymongo import *
'''
修改方法:
update_one()修改满足条件的文档集中的第一条文档
update_many()修改满足条件的文档集中的所有文档
注意:使用$set操作符修改特定属性的值,否则会修改整个文档
'''
def update():
try:
# 1 创建连接对象
client = MongoClient(host="localhost", port=27017)
# 2 获取数据库,
# 如果这个数据库不存在,就在内存中虚拟创建
# 当在库里创建集合的时候,就会在物理真实创建这个数据库
db = client.demo # 使用demo数据库
# 修改数据
# 修改第一条符合条件的数据,传入条件和修改结果
db.stu.update_one({"age": 18},{"$set": {"age": 100}}) # 把年龄是18的第一条年龄改成100
# 所有符合条件数据都修改
# db.stu.update_many({"age": 18},{"$set": {"age": 100}}) # 年龄18的所有数据年龄改成100
except Exception as e:
print(e)
if __name__ == '__main__':
update()
9、删除方法
- delete_one()删除满足条件的文档集中第一条文档
- delete_many()删除满足条件的所有文档
- 注意:使用$set操作符修改特定属性的值,否则会修改整个文档
from pymongo import *
'''
删除方法:
delete_one()删除满足条件的文档集中第一条文档
delete_many()删除满足条件的所有文档
注意:使用$set操作符修改特定属性的值,否则会修改整个文档
'''
def delete():
try:
# 1 创建连接对象
client = MongoClient(host="localhost", port=27017)
# 2 获取数据库,
# 如果这个数据库不存在,就在内存中虚拟创建
# 当在库里创建集合的时候,就会在物理真实创建这个数据库
db = client.demo # 使用demo数据库
# 修改数据
# 修改第一条符合条件的文档删除
db.stu.delete_one({"age": 18}) # 把年龄是18的第一条文档删除
# 所有符合条件数据都删除
db.stu.delete_many({"age": 18}) # 年龄18的所有文档删除
except Exception as e:
print(e)
if __name__ == '__main__':
delete()