10高效存储MongoDB
当我们成功提取了数据之后,该往哪里存放呢?
用文本文件当然是可以的,但文本存储不方便检索
有没有既方便存,又方便检索的存储方式呢?——MongoDB
MongoDB是由C++语言编写的非关系型数据库
是一个基于分布式文件存储的开源数据库系统
其内容存储形式类似JSON对象,它的字段值可以包含其他文档、数组、文档数组
为什么不用MySQL?
mysql对于一些结构化或嵌套类型的数据存储不太方便,而且需要额外维护字段信息,相对麻烦
MongoDB适合存储这类数据
准备工作
开始之前,请确保你已经安装好了MongoDB并启动了其服务,同时安装好了Python的PyMongo库
MongoDB安装教程:https://www.cnblogs.com/TM0831/p/10606624.html
安装好之后,我们需要把MongoDB服务启动起来
- 注意:这里我们为了学习,仅使用MongoDB最基本的单机版,MongoDB还有主从复制、副本集、分片集群架构,可用性可靠性更好,如有需要可以自行搭建相应的集群进行使用
启动完成之后,它会默认在本地localhost的27017端口上运行
接下来我们需要安装PyMongo库,它是Python用来操作MongoDB的第三方库
pip install pymongo
连接MongoDB
连接MongoDB时,我们需要使用PyMongo库里面的MongoClient
一般来说,我们需要向其传入MongoDB的IP及端口
其中第一个参数为地址host,第二个参数为端口port(默认27017)
import pymongo
client = pymongo.MongoClient(host='localhost',port=27017)
这样就可以创建MongoDB的连接对象了
MongoClient的第一个参数host还可以直接传入MongoDB的连接字符串,它以mongodb开头
client = MongoClient('mongodb://localhost:27017/')
也可以达到同样的连接效果
指定数据库
MongoDB中可以建立多个数据库
我们需要指定操作其中一个数据库,以test数据库作为指定使用的例子
db = client.test
这里调用client的test属性即可返回test数据库
还有一种等价的指定方式
db = client['test']
指定集合
MongoDB的每个数据库中包含了许多集合**(collection)**
它们类似于关系型数据库(mysql、SQL Server…)中的表
我们指定一个名称为students的集合,与指定数据库类似,指定集合也有两种方式
collection = db.students
或者
collection = db['students']
这样我们便声明了一个Collection对象
插入数据
我们对students这个集合新建一条学生数据,这条数据以字典形式表示
student = {
'id': '20170101',
'name': 'Jordan',
'age': 20,
'gender': 'male'
}
数据制定了学生的学好、姓名、年龄和性别。
接下来,我们直接调用 collection的insert方法即可插入数据
result = collection.insert(student)
print(result)
在MongoDB中,每条数据其实都有一个_id属性来唯一标识
如果没有显式(清楚且明确的指定了实现内容) 指明该属性,MongoDB会自动产生一个ObjectId类型的_id属性
insert()方法会在执行后返回_id值
我们也可以同时插入多条数据,只需要以列表形式传递即可
student1 = {
'id': '20170102',
'name': 'Leon',
'age': 22,
'gender': 'male'
}
student2 = {
'id': '20170203',
'name': 'Mike',
'age': 21,
'gender': 'male'
}
result = collection.insert([student1,student2])
print(result)
返回结果是对应的_id的集合
DeprecationWarning: insert is deprecated. Use insert_one or insert_many instead
实际上,在PyMongo中,官方已经不推荐使用insert方法了
目前官方推进使用insert_one 和 insert_many方法来分别插入单条记录和多条记录
student = {
'id': '20170204',
'name': 'Tom',
'age': 25,
'gender': 'male'
}
result = collection.insert_one(student)
print(result)
print(result.inserted_id)
与insert方法不同,这次返回的是InsertOneResult对象
我们可以调用其inserted_id属性获取_id
对于insert_many方法,我们可以将数据以列表形式传递
student1 = {
'id': '20170105',
'name': 'Jack',
'age': 20,
'gender': 'male'
}
student2 = {
'id': '20170206',
'name': 'Xiaoming',
'age': 21,
'gender': 'male'
}
result = collection.insert_many([student1,student2])
print(result)
print(result.inserted_ids)
该方法返回的类型是InsertManyResult,调用inserted_ids属性可以获取插入数据的_id列表
查询
插入数据后,我们可以利用find_one或find方法进行查询
- find_one查询得到的是单个结果
- find则返回一个生成器对象
result = collection.find_one({'name':'Leon'})
print(type(result))
print(result)
我们查询name为Leon的数据,它的返回结果是字典类型
可以发现,它多了_id属性,这就是MongoDB在插入过程中自动添加的
我们还可以根据ObjectId来查询,此时需要调用bson库里面的objectid
from bson.objectid import ObjectId
result = collection.find_one({'_id':ObjectId('602e2e28df03b698a534a0b2')})
如果查询结果不存在,则会返回None
对于多条数据的查询,我们可以使用find方法。
例如,查找年龄为20的数据
results = collection.find({'age':20})
print(results)
for result in results:
print(result)
返回Cursor类型,它相当于一个生成器,我们需要遍历获取的所有结果,其中每个结果都是字典类型
查询年龄大于20的数据
results = collection.find({'age':{'$gt':20}})
这里查询条件的键值已经不是单纯的数字了,而是一个字典,其键名为比较符号**$gt**,意思是大于,键值为20
比较符号归纳如下
还可以进行正则匹配查询,例如,查询名字以M开头的学生数据
results = collection.find({'name':{'$regex':'^M.*'}})
使用$regex来指定正则匹配,^M.*代表以M开头的正则表达式
功能符号归类如下
这些操作的更详细用法,参考https://docs.mongodb.com/manual/reference/operator/query/
计数
要统计查询结果有多少条数据,可以调用count方法
我们统计所有数据条数
count = collection.find().count()
print(count)
还可以统计符合某个条件的数据
count = collection.find({'age':21}).count()
print(count)
排序
可以调用sort方法,并在其中传入排序的字段及升降序标志
results = collection.find().sort('name',pymongo.ASCENDING)
print([result['name']for result in results])
这里我们调用pymongo.ASCENDING指定升序,如果要降序排列,可以传入pymongo.DESCENDING
偏移
某些情况下,我们可能只需要取某几个元素,利用skip方法偏移几个位置,比如偏移2,就代表忽略前两个元素,得到第3个及以后的元素
results = collection.find().sort('name',pymongo.ASCENDING).skip(2)
print([result['name']for result in results])
我们还可以用limit方法指定要取的结果个数
results = collection.find().sort('name',pymongo.ASCENDING).skip(2).limit(2)
print([result['name']for result in results])
加了limit方法,限制之后,就会截取两个结果返回
-
值得注意的是,在数据量非常庞大的时候,比如在查询千万、亿级别的数据库时,最好不要使用大的偏移量,这样很可能导致内存溢出
-
此时可以使用如下操作来查询
from bson.objectid import ObjectId
collection.find({'_id:{'$gt':ObjectId('602e2e28df03b698a534a0b2')}'})
这时需要记录好上次查询的_id
更新
对于数据更新,我们可以使用update方法,指定更新的条件和更新后的数据即可
condition = {'name':'Mike'}
student = collection.find_one(condition)
student['age']= 25
result = collection.update(condition,student)
print(result)
我们要更新name为Mike的数据的年龄:首先指定查询条件,然后将数据查询出来,修改年龄后调用update方法将原条件和修改后的数据传入
返回结果是字典形式,ok代表执行成功,nModified代表影响的数据条数
我们也可以使用**$set操作符**对数据进行更新
result = collection.update(condition,{'$set':student})
这样可以只更新student字典内存在的字段
如果原先还有其他字段,则不会更新,也不会删除
而如果不用$set的话,则会把之前的数据全部用student字典替换
如果原本存在其他字段,则会被删除
另外,update方法也是官方不推荐使用的方法。推荐使用update_one和update_many方法
用法更加严格,它们的第2个参数需要使用$类型操作符作为字典的键名
condition = {'name':'Mike'}
student = collection.find_one(condition)
student['age'] = 26
result = collection.update_one(condition,{'$set':student})
print(result)
print(result.matched_count,result.modified_count)
调用update_one方法,使得第2个参数不能再直接传入修改后的字典,而是需要使用{’$set’:student}这样的形式
其返回结果是UpdateResult类型。然后分别调用matched_count和modified_count属性,可以获得匹配的数据条数和影响的数据条数
再看一个例子
condition = {'age':{'$gt':20}}
result = collection.update_one(condition,{'$inc':{'age':1}})
print(result)
print(result.matched_count,result.modified_count)
这里指定查询条件为年龄大于20,然后更新条件为
{’$inc’:{‘age’:1}},表示年龄加1,执行之后会将第一条符合条件的数据年龄加1
匹配条数为1条,影响条数也为1条
如果调用update_many方法,则会将所有符合条件的数据都更新
condition = {'age':{'$gt':20}}
result = collection.update_many(condition,{'$inc':{'age':1}})
print(result)
print(result.matched_count,result.modified_count)
这时所有匹配到的数据都会被更新
删除
删除操作比较简单,直接调用remove方法指定删除的条件即可,此时符合条件的数据均会被删除
result = collection.remove({'name':'Mike'})
print(result)
这里官方依然推荐两个新方法——delete_one、delete_many
result = collection.delete_one({'name':'Xiaoming'})
print(result)
print(result.deleted_count)
result = collection.delete_many({'age':{'$gt':25}})
print(result.deleted_count)
delete_one即删除第一个符合条件的数据,delete_many即删除所有符合条件的数据
它们返回结果都是DeleteResult类型,可以调用deleted_count属性获取删除的数据条数
其他操作
PyMongo还提供了一些组合方法
-
find_one_and_delete 查找后删除
-
find_one_and_replace 查找后替换
-
find_one_and_update 查找后更新
还可以对索引进行操作
create_index 、 create_indexes 、drop_index等
PyMongo还提供了一些组合方法
-
find_one_and_delete 查找后删除
-
find_one_and_replace 查找后替换
-
find_one_and_update 查找后更新
还可以对索引进行操作
create_index 、 create_indexes 、drop_index等
PyMongo的详细用法,参见官方文档http://api.mongodb.com/python/current/api/pymongo/collection.html
数据库和集合本身的操作,参见官方文档http://api.mongodb.com/python/current/api/pymongo/