【10】高效存储MongoDB的用法

目录

一、什么是MongoDB

二、准备工作

(1)安装MongoDB

​(2)安装pymongo库

三、连接MongoDB

四、指定数据库

五、指定集合

六、插入数据

[(1) insert 方法](#(1) insert 方法)

[(2)insert_one() 和 insert_many() 方法](#(2)insert_one() 和 insert_many() 方法)

七、查询

(1)find_one()

(2)ObjectId

(3)find()方法

八、计数

九、排序

十、偏移

十一、更新

(1)update()方法

[(2)update_one() 方法和 update_many() 方法](#(2)update_one() 方法和 update_many() 方法)

十二、删除

[(1) remove() 方法](#(1) remove() 方法)

[(2)delete_one() 和 delete_many()](#(2)delete_one() 和 delete_many())

十三、其他操作


在第9讲中我们学会了如何利用pyquery提取数据信息,那么提取得到的数据该如何存放呢??本节介绍的MongoDB就是一种既方便存储又方便检索的存储方式

一、什么是MongoDB

在这一节中,我们就来看看 Python 3 下 MongoDB 的存储操作。

二、准备工作

(1)安装MongoDB

在开始之前,请确保已经安装好了 MongoDB 并启动了其服务

安装以及启动方式参考:

Windows(超详细保姆级教学)安装mongodb数据库_mongodb windows安装-CSDN博客

windows环境下启动mongodb服务_windows非正常关机导致mongodb服务手动才能启动-CSDN博客

(2)安装pymongo库

python中安装 pymongo库参考:Python3网络爬虫开发实战 1.5.2-PyMongo的安装 | 静觅

三、连接MongoDB

连接 MongoDB 时,我们需要使用 PyMongo 库里面的 MongoClient。一般来说,传入 MongoDB 的 IP 及端口即可,其中第一个参数为地址 host,第二个参数为端口 port(如果不给它传递参数,默认是 27017):

python 复制代码
import pymongo
client = pymongo.MongoClient(host='localhost', port=27017)

这样就可以创建 MongoDB 的连接对象了。

另外,MongoClient 的第一个参数 host 还可以直接传入 MongoDB 的连接字符串,它以 mongodb 开头,例如:

python 复制代码
client = MongoClient('mongodb://localhost:27017/')

这也可以达到同样的连接效果。

四、指定数据库

MongoDB 中可以建立多个数据库,接下来我们需要指定操作哪个数据库。这里我们以 test 数据库为例来说明,下一步需要在程序中指定要使用的数据库:

python 复制代码
db = client.test

这里调用client 的 test 属性即可返回 test 数据库。当然,我们也可以这样指定:

python 复制代码
db = client['test']

五、指定集合

MongoDB 的每个数据库又包含许多集合(collection),它们类似于关系型数据库中的表。下一步需要指定要操作的集合,这里指定一个集合名称为 students。与指定数据库类似,指定集合也有两种方式:

python 复制代码
collection = db.students
# collection = db['students']

六、插入数据

(1) insert 方法

接下来,便可以插入数据了。对于 students 这个集合,新建一条学生数据,这条数据以字典形式表示:

python 复制代码
student = {
    'id': '20170101',
    'name': 'Jordan',
    'age': 20,
    'gender': 'male'
}

这里指定了学生的学号、姓名、年龄和性别。接下来,直接调用 collection 的 insert 方法即可插入数据,代码如下

python 复制代码
result = collection.insert(student)
print(result)

在 MongoDB 中,每条数据其实都有一个 id 属性来唯一标识。如果没有显式指明该属性,MongoDB 会自动产生一个 ObjectId 类型的 id 属性。insert() 方法会在执行后返回_id 值。

运行结果如下:

python 复制代码
5932a68615c2606814c91f3d

当然,我们也可以同时插入多条数据,只需要以列表形式传递即可,示例如下:

python 复制代码
student1 = {
    'id': '20170101',
    'name': 'Jordan',
    'age': 20,
    'gender': 'male'
}

student2 = {
    'id': '20170202',
    'name': 'Mike',
    'age': 21,
    'gender': 'male'
}

result = collection.insert([student1, student2])
print(result)

返回结果是对应的_id 的集合:

python 复制代码
[ObjectId('5932a80115c2606a59e8a048'), ObjectId('5932a80115c2606a59e8a049')]

(2)insert_one() 和 insert_many() 方法

实际上,在 PyMongo 3.x 版本中,官方已经不推荐使用 insert() 方法了。当然,继续使用也没有什么问题。官方推荐使用insert_one() 和 insert_many() 方法来分别插入单条记录和多条记录,示例如下:

python 复制代码
student = {
    'id': '20170101',
    'name': 'Jordan',
    'age': 20,
    'gender': 'male'
}

result = collection.insert_one(student)
print(result)
print(result.inserted_id)

与 insert() 方法不同,这次返回的是 InsertOneResult 对象,我们可以调用其 inserted_id 属性获取_id。

对于 insert_many() 方法,我们可以将数据以列表形式传递,示例如下:

python 复制代码
student1 = {
    'id': '20170101',
    'name': 'Jordan',
    'age': 20,
    'gender': 'male'
}

student2 = {
    'id': '20170202',
    'name': 'Mike',
    'age': 21,
    'gender': 'male'
}

result = collection.insert_many([student1, student2])
print(result)
print(result.inserted_ids)

该方法返回的类型是 InsertManyResult,调用 inserted_ids 属性可以获取插入数据的_id 列表。

七、查询

(1)find_one()

插入数据后,我们可以利用find_one() 或 find() 方法进行查询,其中 find_one() 查询得到的是单个结果,find() 则返回一个生成器对象。示例如下:

python 复制代码
result = collection.find_one({'name': 'Mike'})
print(type(result))
print(result)

这里我们查询 name 为 Mike 的数据,它的返回结果是字典类型,运行结果如下:

python 复制代码
<class 'dict'>
{'_id': ObjectId('5932a80115c2606a59e8a049'), 'id': '20170202', 'name': 'Mike', 'age': 21, 'gender': 'male'}

发现,它多了_id 属性,这就是 MongoDB 在插入过程中自动添加的。

(2)ObjectId

此外,我们也可以根据 ObjectId来查询,此时需要使用 bson 库里面的 objectid:

python 复制代码
from bson.objectid import ObjectId

result = collection.find_one({'_id': ObjectId('593278c115c2602667ec6bae')})
print(result)

其查询结果依然是字典类型,具体如下:

python 复制代码
{'_id': ObjectId('593278c115c2602667ec6bae'), 'id': '20170101', 'name': 'Jordan', 'age': 20, 'gender': 'male'}

当然,如果查询结果不存在,则会返回 None。

(3)find()方法

对于多条数据的查询,我们可以使用find() 方法。例如,这里查找年龄为 20 的数据,示例如下:

python 复制代码
results = collection.find({'age': 20})
print(results)
for result in results:
    print(result)

运行结果如下:

python 复制代码
<pymongo.cursor.Cursor object at 0x1032d5128>
{'_id': ObjectId('593278c115c2602667ec6bae'), 'id': '20170101', 'name': 'Jordan', 'age': 20, 'gender': 'male'}
{'_id': ObjectId('593278c815c2602678bb2b8d'), 'id': '20170102', 'name': 'Kevin', 'age': 20, 'gender': 'male'}
{'_id': ObjectId('593278d815c260269d7645a8'), 'id': '20170103', 'name': 'Harden', 'age': 20, 'gender': 'male'}

返回结果是 Cursor 类型,它相当于一个生成器,我们需要遍历取到所有的结果,其中每个结果都是字典类型。

如果要查询年龄大于 20 的数据,则写法如下:

python 复制代码
results = collection.find({'age': {'$gt': 20}})

这里查询的条件键值已经不是单纯的数字了,而是一个字典,其键名为比较符号 $gt,意思是大于,键值为 20。

比较符号

符  号 含  义 示  例
$lt 小于 {'age': {'$lt': 20}}
$gt 大于 {'age': {'$gt': 20}}
$lte 小于等于 {'age': {'$lte': 20}}
$gte 大于等于 {'age': {'$gte': 20}}
$ne 不等于 {'age': {'$ne': 20}}
$in 在范围内 {'age': {'$in': 20, 23}}
$nin 不在范围内 {'age': {'$nin': 20, 23}}

八、计数

要统计查询结果有多少条数据,可以调用 count() 方法。比如,统计所有数据条数:

python 复制代码
count = collection.find().count()
print(count)

或者统计符合某个条件的数据:

python 复制代码
count = collection.find({'age': 20}).count()
print(count)

运行结果是一个数值,即符合条件的数据条数。

九、排序

排序时,直接调用 sort() 方法,并在其中传入排序的字段及升降序标志即可。示例如下:

python 复制代码
results = collection.find().sort('name', pymongo.ASCENDING)
print([result['name'] for result in results])

运行结果如下:

python 复制代码
['Harden', 'Jordan', 'Kevin', 'Mark', 'Mike']

这里我们调用 pymongo.ASCENDING 指定升序。如果要降序排列,可以传入 pymongo.DESCENDING。

十、偏移

在某些情况下,我们可能想只取某几个元素,这时可以利用 skip() 方法偏移几个位置,比如偏移 2,就忽略前两个元素,得到第三个及以后的元素:

python 复制代码
results = collection.find().sort('name', pymongo.ASCENDING).skip(2)
print([result['name'] for result in results])

运行结果如下:

python 复制代码
['Kevin', 'Mark', 'Mike']

另外,还可以用 limit() 方法指定要取的结果个数,示例如下:

python 复制代码
results = collection.find().sort('name', pymongo.ASCENDING).skip(2).limit(2)
print([result['name'] for result in results])

运行结果如下:

python 复制代码
['Kevin', 'Mark']

如果不使用 limit() 方法,原本会返回三个结果,加了限制后,会截取两个结果返回。

值得注意的是,在数据库数量非常庞大的时候,如千万、亿级别,最好不要使用大的偏移量来查询数据,因为这样很可能导致内存溢出。此时可以使用类似如下操作来查询:

python 复制代码
from bson.objectid import ObjectId
collection.find({'_id': {'$gt': ObjectId('593278c815c2602678bb2b8d')}})

这时需要记录好上次查询的_id。

十一、更新

(1)update()方法

对于数据更新,我们可以使用update() 方法,指定更新的条件和更新后的数据即可。例如:

python 复制代码
condition = {'name': 'Kevin'}
student = collection.find_one(condition)
student['age'] = 25
result = collection.update(condition, student)
print(result)

这里我们要更新 name 为 Kevin 的数据的年龄:首先指定查询条件,然后将数据查询出来,修改年龄后调用 update() 方法将原条件和修改后的数据传入。

运行结果如下:

python 复制代码
{'ok': 1, 'nModified': 1, 'n': 1, 'updatedExisting': True}

返回结果是字典形式,ok 代表执行成功,nModified 代表影响的数据条数。

另外,我们也可以使用 $set 操作符对数据进行更新,代码如下:

python 复制代码
result = collection.update(condition, {'$set': student})

这样可以只更新 student 字典内存在的字段。如果原先还有其他字段,则不会更新,也不会删除。而如果不用 $set 的话,则会把之前的数据全部用 student 字典替换;如果原本存在其他字段,则会被删除。

(2)update_one() 方法和 update_many() 方法

另外,update() 方法其实也是官方不推荐使用的方法。这里也分为 update_one() 方法和 update_many() 方法,用法更加严格,它们的第二个参数需要使用 $ 类型操作符作为字典的键名,示例如下:

python 复制代码
condition = {'name': 'Kevin'}
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() 方法,第二个参数不能再直接传入修改后的字典,而是需要使用 {'$set': student} 这样的形式,其返回结果是 UpdateResult 类型。然后分别调用 matched_count 和 modified_count 属性,可以获得匹配的数据条数和影响的数据条数。

运行结果如下

python 复制代码
<pymongo.results.UpdateResult object at 0x10d17b678>
1 0

我们再看一个例子

python 复制代码
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。

运行结果如下:

python 复制代码
<pymongo.results.UpdateResult object at 0x10b8874c8>
1 1

可以看到匹配条数为 1 条,影响条数也为 1 条。

如果调用 update_many() 方法,则会将所有符合条件的数据都更新,示例如下:

python 复制代码
condition = {'age': {'$gt': 20}}
result = collection.update_many(condition, {'$inc': {'age': 1}})
print(result)
print(result.matched_count, result.modified_count)

这时匹配条数就不再为 1 条了,运行结果如下:

python 复制代码
<pymongo.results.UpdateResult object at 0x10c6384c8>
3 3

可以看到,这时所有匹配到的数据都会被更新。

十二、删除

(1) remove() 方法

删除操作比较简单,直接调用 remove() 方法指定删除的条件即可,此时符合条件的所有数据均会被删除。示例如下:

python 复制代码
result = collection.remove({'name': 'Kevin'})
print(result)

运行结果如下:

python 复制代码
{'ok': 1, 'n': 1}

(2)delete_one() 和 delete_many()

另外,这里依然存在两个新的推荐方法 ------delete_one() 和 delete_many()。示例如下:

python 复制代码
result = collection.delete_one({'name': 'Kevin'})
print(result)
print(result.deleted_count)
result = collection.delete_many({'age': {'$lt': 25}})
print(result.deleted_count)

运行结果如下:

python 复制代码
<pymongo.results.DeleteResult object at 0x10e6ba4c8>
1
4

delete_one() 即删除第一条符合条件的数据,delete_many() 即删除所有符合条件的数据。它们的返回结果都是 DeleteResult 类型,可以调用 deleted_count 属性获取删除的数据条数。

十三、其他操作

相关推荐
liangsheng_g3 分钟前
Spring事务传播行为分派与挂起恢复源码实战
数据库·sql·spring
蓝速科技17 分钟前
信创终端 POC 测试实战与选型避坑指南丨蓝速科技
运维·数据库·人工智能·科技·自然语言处理
风哥2号32 分钟前
数据库教程FGMT29‑Linux平台MySQL5.7安装配置与管理入门
数据库
杨云龙UP1 小时前
MySQL Host is blocked because of many connection errors 导致 JDBC 连接失败排查与解决
linux·运维·网络·数据库·sql·mysql·登录失败
这个DBA有点耶3 小时前
数据库数据同步解决方案怎么选?6款主流工具横向对比与信创选型指南
数据库·架构·dba
刃神太酷啦3 小时前
Redis 核心进阶:哨兵、集群、缓存问题与分布式锁详解----《Hello Redis!》(6)
linux·c语言·数据库·c++·redis·分布式·缓存
小雷信息医学3 小时前
不会写复杂代码也能发 SCI?手把手教你用 InSpireR 交互系统一键提取、合并与导出临床科研宽表【第三章】
数据库
旺仔不是程序员3 小时前
复合索引最左前缀原则:PostgreSQL 的 WHERE 为什么必须命中第一列
数据库·后端·sql
旺仔不是程序员3 小时前
字段类型不一致:PostgreSQL 报错与索引失效的第一元凶
数据库·后端·sql
白远山3 小时前
货运跑腿搬家平台开发实战:从需求分析到落地部署指南
数据库·数据挖掘·需求分析