MongoDB的介绍
MongoDB是一个基于分布式文件存储的nosql数据库。在处理大数据的时候会比MySQL更有优势。爬虫的数据如果上了一个量级,可能用MongoDB会比MySQL更好
SQL和NoSQL的主要区别
- 在SQL中层级关系:数据库->表->数据
- 在NoSQL中是:数据库->集合->文档
MongoDB的优势
1.无数据结构限制
- 没有表结构的概念,每条记录可以有完全不同的结构
- 业务开发方便快捷
{name:'小明',sex:'男'}
{name:'居然',address:'东北'}
{name:'小红',home:[{'山东'},{江西}]}
2.大数据量和高性能
- nosql数据库都具有非常高的读写性能,尤其在大数量下表现优秀
3.良好的支持
- 完善的文档
- 齐全的驱动支持
MongoDB在Ubuntu中安装
在Linux中安装MongoDB
sudo apt-get install mongodb
开启服务
sudo service mongodb start
关闭服务
sudo service mongodb stop
重启服务
sudo service mongodb restart
注意:如果是系统非正常关闭,这样启动会报错,由于mongodb自动被锁上了,这是需要进入mongodb数据库文件所在的目录(/var/lib/mongodb/),删除目录中的mongodb.lock文件,然后再进行上述操作。
如果想让远程连接
需要修改 /etc/mongodb.conf
打开文件:
sudo vim /etc/mongodb.conf
注释掉 bind 127.0.0.1
MongoDB在Windows中安装
网址:https://www.mongodb.com/download-center/community
Windows安装MongoDB:https://www.cnblogs.com/chy18883701161/p/11100560.html
运行MongoDB
1.把MongoDB的bin目录加入到环境变量中
2.执行命令
mongod --dbpath D:\MongoDB\data # 启动
连接MongoDB
在环境变量设置好的前提下,使用以下命令mongo
就可以进入到mongo的操作终端了
查看帮助命令
mongo -help
MongoDB概念介绍
SQL概念 | MongoDB概念 | 解释 |
---|---|---|
database | database | 数据库 |
table | collection | 数据库表/集合 |
row | document | 数据记录行/文档 |
column | field | 字段/域 |
index | index | 索引 |
primary key | primary key | 主键 |
MongoDB三元素
三元素:数据库、集合、文档
- 文档:就是关系型数据库中的一行。文档是一个对象,由键值对构成,是json的扩展形式
{"name": "abc", "gender": 1}
- 集合:就是关系型数据库中的表。可以存储多个文档,结构可以不固定。
{"name": "abc", "gender": 1}
{"name": "abc", "age": 18}
{"title": "abc", "price": 1}
mongoDB中数据库的基本使用
-
查看数据库
-
- show dbs
-
切换数据库
-
- use 数据库
-
查看当前的数据库
-
- db
-
删除数据库
-
- db.dropDatabase()
-
会自动创建数据库
-
- use 数据库
-
查看集合
-
- show tables/show collections
-
退出数据库
-
- db.shutdownServer()
MongoDB中集合的基础命令
不手动创建集合,向不存在的集合中第一次加入数据时,集合会被创建出来!!!!
手动创建集合 : db.createCollection(name,options)
- name: 要创建的集合名称
- options: 可选参数, 指定有关内存大小及索引的选项
db.createCollection('sub',{capped:true,size:10})
- 参数capped:默认值为false表示不设置上限,值为true表示设置上限
- 参数size:当capped值为true时,需要制定此参数。表示上限大小,当文档达到上限时,会将之前的数据覆盖,单位为字节
查看集合
show collections
删除集合:db.集合名称.drop()
MongoDB的数据类型
-
String:字符串,必须是有效的UTF-8
-
Boolean:存储一个布尔值,true或者false
-
Integer:整数可以是32位或64位,这取决于服务器
-
Double:存储浮点数
-
Arrays:数组或列表
-
Object:嵌入式文档
-
Null:存储Null值
-
Timestamp:时间戳, 表示从1970-1-1到现在的总秒数
-
Object ID是一个12字节的十六进制数
-
- 前4个字节为当前时间戳
- 接下来3个字节的机器ID
- 接下来的2个字节中MongoDB的服务进程id
- 最后3个字节是简单的增量值
MongoDB的增删改查
数据库命名规范
1.不能是空字符串
2.不得含有特殊字符
3.应全部小写
4.最多64个字节
5.数据库名不能与现有系统保留库同名,如admin,local
MongoDB的增删改查
mongoDB中一张表称为一个集合
mongoDB插入数据
db.集合名.insert({}) 数据格式为json,id不能重复,支持多条插入数据库
单条插入数据
db.juran_collection.insert({x:1})
多条插入数据
for(i=3;i<10;i++)db.juran_collection.insert({x:i})
mongodb的保存
命令:db.集合名称.save(document)
db.stu.save({_id:ObjectId("5f169b37d74866264ed9a7db"), name:'gj', gender:2})
db.stu.save({name:'gj', gender:2})
db.stu.find()
MongoDB查询数据
测试数据
db.stu.insert([{"name" : "张三", "hometown" : "长沙", "age" : 20, "gender" : true },
{"name" : "老李", "hometown" : "广州", "age" : 18, "gender" : false },
{"name" : "王麻子", "hometown" : "北京", "age" : 18, "gender" : false },
{"name" : "刘六", "hometown" : "深圳", "age" : 40, "gender" : true },
{"name" : "居然", "hometown" : "哈尔滨", "age" : 16, "gender" : true },
{"name" : "小永", "hometown" : "广州", "age" : 45, "gender" : true },
{"name" : "老amy", "hometown" : "衡阳", "age" : 18, "gender" : true }])
查询所有数据
db.juran_collection.find({条件⽂档})
⽅法pretty():将结果格式化
db.集合名称.find({条件⽂档}).pretty()
查询单条数据
db.juran_collection.findOne({条件⽂档})
带有条件的查询
查询x等于100的数据
db.juran_collection.find({x:100})
查询x等于100,y等于99的
db.juran_collection.find({x:100,y:99})
比较运算符
等于:默认是等于判断,没有运算符
小于:$lt
小于等于:$lte
大于:$gt
大于等于:$gte
查询y大于等于18的数据
db.juran_collection.find({y:{$gte:18}})
范围运算符
使用$in,$nin判断是否在某个范围内查询年龄为18、28的学生
db.juran_collection.find({age:{$in:[18,28]}})
逻辑运算符
or:使用$or,值为数组,数组中每个元素为json
db.juran_collection.find({$or:[{age:{$gt:18}},{gender:false}]})
自定义查询
mongo shell 是一个js的执行环境
使用$where 写一个函数, 返回满足条件的数据
查询年龄大于30的学生
db.juran_collection.find({
$where:function() {
return this.age>30;}
})
查询结果操作
查出的数据求总数
db.juran_collection.find().count()
limit和skip
limit用于读取指定数量的文档
db.juran_collection.find().limit(2)
skip用于跳过指定数量的文档
db.juran_collection.find().skip(2)
limit和skip同时使用
db.juran_collection.find().skip(2).limit(2)
映射
指定返回的字段,如果为1则返回改字段,如果为0则除了改字段外所有字段返回。id如果没写会默认返回
db.juran_collection.find({},{_id:1})
排序
按照年龄升序排序
db.juran_collection().find().sort({age:1})
按照年龄降序排序
db.juran_collection().find().sort({age:-1})
修改数据
db.集合名称.update({query}, {update}, {multi: boolean})
- 参数query:查询条件
- 参数update:更新操作符
- 参数multi:可选,默认是false,表示只更新找到的第一条数据,值为true表示把满足条件的数据全部更新
db.juran_collection.insert({x:100,y:100,z:100})
{ "_id" : ObjectId("59b297dd8fa0c171faae5bc8"), "x" : 100, "y" : 100, "z" : 100 }
db.juran_collection.update({x:100},{y:99})
修改后数据变为
{ "_id" : ObjectId("59b297dd8fa0c171faae5bc8"), "y" : 99 }
部分更新
db.juran_collection.update({x:100},{$set:{y:99}})
如果y:100数据不存在,就插入y:101这条数据,第三个参数为true
db.juran_collection.update({y:100},{y:101},true)
更新多条
db.juran_collection.update({y:99},{$set:{y:101}},{multi:true})
删除数据
db.juran_collection.remove({条件},{justOne:true}) mongoDB为了防止误删除,条件必须写
db.juran_collection.remove() 删除所有数据,索引不会删除
db.juran_collection.remove({x:100})
删除表
db.juran_collection.drop()
练习
测试数据
var persons = [{
name:"jim",
age:25,
email:"75431457@qq.com",
c:89,m:96,e:87,
country:"USA",
books:["JS","C++","EXTJS","MONGODB"]
},
{
name:"tom",
age:25,
email:"214557457@qq.com",
c:75,m:66,e:97,
country:"USA",
books:["PHP","JAVA","EXTJS","C++"]
},
{
name:"lili",
age:26,
email:"344521457@qq.com",
c:75,m:63,e:97,
country:"USA",
books:["JS","JAVA","C#","MONGODB"]
},
{
name:"zhangsan",
age:27,
email:"2145567457@qq.com",
c:89,m:86,e:67,
country:"China",
books:["JS","JAVA","EXTJS","MONGODB"]
},
{
name:"lisi",
age:26,
email:"274521457@qq.com",
c:53,m:96,e:83,
country:"China",
books:["JS","C#","PHP","MONGODB"]
},
{
name:"wangwu",
age:27,
email:"65621457@qq.com",
c:45,m:65,e:99,
country:"China",
books:["JS","JAVA","C++","MONGODB"]
},
{
name:"zhaoliu",
age:27,
email:"214521457@qq.com",
c:99,m:96,e:97,
country:"China",
books:["JS","JAVA","EXTJS","PHP"]
},
{
name:"piaoyingjun",
age:26,
email:"piaoyingjun@uspcat.com",
c:39,m:54,e:53,
country:"Korea",
books:["JS","C#","EXTJS","MONGODB"]
},
{
name:"lizhenxian",
age:27,
email:"lizhenxian@uspcat.com",
c:35,m:56,e:47,
country:"Korea",
books:["JS","JAVA","EXTJS","MONGODB"]
},
{
name:"lixiaoli",
age:21,
email:"lixiaoli@uspcat.com",
c:36,m:86,e:32,
country:"Korea",
books:["JS","JAVA","PHP","MONGODB"]
},
{
name:"zhangsuying",
age:22,
email:"zhangsuying@uspcat.com",
c:45,m:63,e:77,
country:"Korea",
books:["JS","JAVA","C#","MONGODB"]
}]
for(var i = 0;i<persons.length;i++){
db.persons.insert(persons[i])
}
var persons = db.persons.find({name:"jim"})
while(persons.hasNext()){
obj = persons.next();
print(obj.books.length)
}
题目
1.查询年龄大于25小于27的name,age
2.查询出不是美国的name
3.查询国籍是中国或者美国的学生信息
4.查询语文成绩大于85或者英语成绩大于90的学生信息
5.查询出名字中存在"li"的学生信息
6.查询喜欢看MONGODB和PHP的学生
7.查询第二本书是JAVA的学生信息
8.查询喜欢的书数量是4本的学生
9.查询出persons中一共有多少国家分别是什么
MongoDB中的聚合命令
聚合
聚合是基于数据处理的聚合管道,每个文档通过一个由多个阶段组成的管道,可以对每个阶段的管道进行分组、过滤等功能,然后经过一系列的处理,输出相应的结果
常用的管道
$group:将集合中的文档分组,可用于统计结果
$match:过滤数据,只输出符合条件的文档
$project:修改输入文档的结构
$sort:将输入文档排序后输出
$limit:限制聚合管道返回的文档书
$skip:跳过指定数量的文档,并返回余下的文档
测试数据
db.stu.insert({name:"a", hometown: '东北', age: 20, gender: true})
db.stu.insert({name:"b", hometown: '长沙', age: 18, gender: false})
db.stu.insert({name:"c", hometown: '武汉', age: 18, gender: false})
db.stu.insert({name:"d", hometown: '华山', age: 40, gender: true})
db.stu.insert({name:"e", hometown: '山东', age: 16, gender: true})
db.stu.insert({name:"f", hometown: '江苏', age: 45, gender: true})
db.stu.insert({name:"g", hometown: '大理', age: 18, gender: true})
表达式
处理输⼊⽂档并输出
语法:表达式:’$列名’
常⽤表达式:
$sum: 计算总和, $sum:1 表示以⼀倍计数
$avg: 计算平均值
$min: 获取最⼩值
$max: 获取最⼤值
$push: 在结果⽂档中插⼊值到⼀个数组中
$first: 根据资源⽂档的排序获取第⼀个⽂档数据
$last: 根据资源⽂档的排序获取最后⼀个⽂档数据
$group
将集合中的文档分组,课用于统计结果
- _id表示分组的依据,使用某个字段的格式为 ‘$字段’
按照gender分组
db.students.aggregate(
{$group:{_id:'$gender',count:{$sum:1}}}
)
按照gender分组,获取不同组的平均年龄
db.students.aggregate(
{$group:{_id:'$gender',count:{$sum:1},avg_age:{$avg:"$age"}}}
)
$match
match是管道命令,能将结果交给后一个管道
查询年龄大于20的学生
db.students.aggregate(
{$match:{age:{$gt:20}}}
)
查询年龄大于20的男生,女生人数
db.students.aggregate(
{$match:{age:{$gt:20}}},
{$group:{_id:'$gender',count:{$sum:1}}}
)
Mongodb的索引操作
1. 为什么mongdb需要创建索引
- 加快查询速度
- 进行数据的去重
2. mongodb创建简单的索引方法
- 语法:
db.集合名.ensureIndex({属性:1})
,1表示升序, -1表示降序
3. 创建索引前后查询速度对比
测试:插入10万条数据到数据库中
插入数据
for(i=0;i<100000;i++){db.test.insert({name:'test'+i,age:i})}
创建索引前
db.test.find({name:'test9999'})
db.test.find({name:'test9999'}).explain('executionStats') # 显示查询操作的详细信息
创建索引
db.test.ensureIndex({name:1})
创建索引后
db.test.find({name:'test9999'}).explain('executionStats')
4. 索引的查看
默认情况下_id是集合的索引
查看方式:db.集合名.getIndexes()
5. 删除索引
语法:db.集合名.dropIndex({'索引名称':1})
db.test.dropIndex({name:1})
db.test.getIndexes()
6. mongodb创建唯一索引
在默认情况下mongdb的索引域的值是可以相同的,创建唯一索引之后,数据库会在插入数据的时候检查创建索引域的值是否存在,如果存在则不会插入该条数据,但是创建索引仅仅能够提高查询速度,同时降低数据库的插入速度。
6.1 添加唯一索引的语法
db.集合名.ensureIndex({"字段名":1}, {"unique":true})
6.2 利用唯一索引进行数据去重
根据唯一索引指定的字段的值,如果相同,则无法插入数据
db.t1.ensureIndex({"name":1}, {"unique":true})
db.t1.insert({name: 'test10000'})
7. 建立复合索引
在进行数据去重的时候,可能用一个域来保证数据的唯一性,这个时候可以考虑建立复合索引来实现。
例如:抓全贴吧信息,如果把帖子的名字作为唯一索引对数据进行去重是不可取的,因为可能有很多帖子名字相同
建立复合索引的语法:db.collection_name.ensureIndex({字段1:1,字段2:1})
8. 建立索引注意点
- 根据需要选择是否需要建立唯一索引
- 索引字段是升序还是降序在单个索引的情况下不影响查询效率,但是带复合索引的条件下会有影响
- 数据量巨大并且数据库的读出操作非常频繁的时候才需要创建索引,如果写入操作非常频繁,创建索引会影响写入速度
MongoDB和Python的交互
MongoDB数据库
pymongo安装
pip install pymongo
连接数据库
方式一
client = MongoClient()
方式二 指定端口和地址
client = MongoClient('localhost',27017)
方式三 使用URI 不是URL
client = MongoClient('mongodb://localhost:27017/')
新增数据
from pymongo import MongoClient
from datetime import datetime
class TestMongo(object):
def __init__(self):
self.client = MongoClient('mongodb://localhost:27017/')
# 也可以指定连接的集合client['admin']['students']
self.db = self.client['admin']
# print(self.client.database_names())
def add_one(self):
post = {'title':'标题','content':'内容','created_at':datetime.now()}
# db.students students 是表明
res = self.db.students.insert_one(post)
return res
def add_more(self):
data_list = [{"name":"test{}".format(i)} for i in range(5)]
res = self.db.students.insert_many(data_list)
return res
mongo = TestMongo()
res = mongo.add_one()
插入的ID
print(res.inserted_id)
查询数据
from bson.objectid import ObjectId
查询一条数据
def get_one(self):
return self.db.students.find_one()
查询多条数据
def get_more(self):
return self.db.students.find()
根据记录的ID查询数据
def get_from_id(self,id):
return self.db.students.find_one({'_id':ObjectId(id)})
查询一条数据
res = mongo.get_one()
查询多条数据
res = mongo.get_more()
for i in res:
print(i)
根据记录的ID查询数据
res = mongo.get_from_id('5b83e8a1b594c32e8c70c1f7')
print(res)
修改数据
修改单条数据
def update(self):
res = self.db.students.update_one({'title':'标题'},{'$set':{'title':'title-2'}})
# 匹配的数据条数
print(res.matched_count)
# 影响的数据条数。
print(res.modified_count)
修改多条
def update_more(self):
res = self.db.students.update_many({},{'$set':{'x':1}})
print(res.matched_count)
print(res.modified_count)
res = self.db.students.update({'x':2},{'$set':{'x':3}},True)
res = mongo.update()
res = mongo.update_more()
删除数据
删除一条
def delete_one(self):
res = self.db.students.delete_one({'title':'title-2'})
print(res.deleted_count)
删除多条
def delete_more(self):
res = self.db.students.delete_many({'x':2})
print(res.deleted_count)
res = mongo.delete_one()
res = mongo.delete_more()