PyMongo 操作文档
实验准备
打开实验环境,在终端输入如下命令启动 MongoDB 服务,进入命令行交互客户端:
$ cd
$ sudo service mongodb start
$ mongo
创建数据
进入 ipython 命令行交互解释器,创建 client 客户端对象:
In [3]: from pymongo import MongoClient
In [4]: client = MongoClient(host='localhost', port=27017)
再次使用 learn 数据库,向数据库的 course 集合中添加数据:
In [6]: db = client.learn
In [7]: course = db.course
In [8]: course.insert_many([
...: {'name': 'Linux 基础入门', 'author': 'James', 'students_count': 1234},
...: {'name': 'Python 简明教程', 'author': 'Wade', 'students_count': 2234},
...: {'name': 'Git 与 GitHub 入门实践', 'author': 'Wade', 'students_count': 8777}
...: ])
Out[8]: <pymongo.results.InsertManyResult at 0x7fac960bf1c8>
在 MongoDB 客户端中验证操作:
> show dbs
admin 0.000GB
config 0.000GB
learn 0.000GB
local 0.000GB
shiyanlou 0.000GB
> use learn
switched to db learn
> show collections
course
> db.course.find().pretty()
{
"_id" : ObjectId("5e4cc6bdf9df85a354b867d3"),
"author" : "James",
"students_count" : 1234,
"name" : "Linux 基础入门"
}
{
"_id" : ObjectId("5e4cc6bdf9df85a354b867d4"),
"author" : "Wade",
"students_count" : 2234,
"name" : "Python 简明教程"
}
{
"_id" : ObjectId("5e4cc6bdf9df85a354b867d5"),
"author" : "Wade",
"students_count" : 8777,
"name" : "Git 与 GitHub 入门实践"
}
>
上一节实验中我们学到了集合的 find 方法可以获取集合中的全部文档,此外我们还可以使用集合的 count_documents 方法获取文档数量,参数为过滤条件。
查询全部文档数量,参数为空字典:
In [9]: course.count_documents({})
Out[9]: 3
查询条件写到字典里,例如查询 author 为 Wade 的课程数量:
In [10]: course.count_documents({'author': 'Wade'})
Out[10]: 2
等同于 MongoDB 客户端中的如下操作:
> db.course.count()
3
> db.course.count({author: 'Wade'})
2
>
查询数据
除了上一节实验中提到的 find 方法,集合对象还提供了 find_one 方法用于查找某一条数据,过滤条件作为参数,例如查询学生数量为 8777 的课程:
In [17]: course.find_one({'students_count': 8777})
Out[17]:
{'_id': ObjectId('5e4cc6bdf9df85a354b867d5'),
'author': 'Wade',
'name': 'Git 与 GitHub 入门实践',
'students_count': 8777}
此外,find 方法也可以提供参数,例如查找 author 为 Wade 的全部课程:
In [18]: results = list(course.find({'author': 'Wade'}))
In [19]: results
Out[19]:
[{'_id': ObjectId('5e4cc6bdf9df85a354b867d4'),
'author': 'Wade',
'name': 'Python 简明教程',
'students_count': 2234},
{'_id': ObjectId('5e4cc6bdf9df85a354b867d5'),
'author': 'Wade',
'name': 'Git 与 GitHub 入门实践',
'students_count': 8777}]
查找 author 为 Wade 且学生数量为 2234 的课程:
In [20]: results = list(course.find(
...: {'author': 'Wade', 'students_count': 2234}
...: ))
In [21]: results
Out[21]:
[{'_id': ObjectId('5e4cc6bdf9df85a354b867d4'),
'author': 'Wade',
'name': 'Python 简明教程',
'students_count': 2234}]
需要注意的是 find_one 返回一条数据,数据类型自然就是字典;而 find 方法返回的数据为迭代器,不论查询结果是一条还是多条,我们都可以使用 list 方法将其转换成列表,列表中的元素是字典。
在 MongoDB 客户端中可以使用 $or 操作符来表示 “或” 条件关系,在 PyMongo 中同样可以,但是需要加引号。
查询 author 为 James 或 students_count 为 2234 的课程:
In [25]: results = course.find(
...: {'$or': [
...: {'author': 'James'},
...: {'students_count': 2234}
...: ]}
...: )
In [26]: list(results)
Out[26]:
[{'_id': ObjectId('5e4cc6bdf9df85a354b867d3'),
'author': 'James',
'name': 'Linux 基础入门',
'students_count': 1234},
{'_id': ObjectId('5e4cc6bdf9df85a354b867d4'),
'author': 'Wade',
'name': 'Python 简明教程',
'students_count': 2234}]
查询 author 为 James 或 students_count 为 2234 的课程的名字:
In [27]: results = course.find(
...: {'$or': [
...: {'author': 'James'},
...: {'students_count': 2234}
...: ]},
...: {'_id': 0, 'name': 1}
...: )
In [28]: list(results)
Out[28]: [{'name': 'Linux 基础入门'}, {'name': 'Python 简明教程'}]
如上所示,第 2 个参数限制查询字段。首先设置去掉 _id 字段,将其设为 0 ;然后将 name 字段设为 1 。
修改数据
同 MongoDB 客户端中的操作一样,使用 update_one 和 update_many 修改文档。这些方法需要提供两个参数:第一个用来确定更新哪一条或哪几条文档,第二个用来提供更新的字段及其值。
举例说明,将 name 为 'Linux 基础入门' 的课程的 students_count 修改为 1000 :
In [34]: course.find_one(
...: {'name': 'Linux 基础入门'}
...: )
Out[34]:
{'_id': ObjectId('5e4cc6bdf9df85a354b867d3'),
'author': 'James',
'name': 'Linux 基础入门',
'students_count': 1234}
In [35]: course.update_one(
...: {'name': 'Linux 基础入门'},
...: {'$set':
...: {'students_count': 1000}
...: }
...: )
Out[35]: <pymongo.results.UpdateResult at 0x7fac86783848>
In [36]: course.find_one(
...: {'name': 'Linux 基础入门'}
...: )
Out[36]:
{'_id': ObjectId('5e4cc6bdf9df85a354b867d3'),
'author': 'James',
'name': 'Linux 基础入门',
'students_count': 1000}
如上所示,update_one 函数的第一个参数很好理解,它与 find 函数所用参数的一样。第二个参数为 {'set 叫做操作符,它作为 key 用来设置字段值,value 是一个嵌套键值对。这与 MongoDB 客户端中的操作几乎一样,唯一的不同之处在于 Python 键值对中所有的 key 都要用引号引起来。
replace_one 方法
在 MongoDB 客户端中我们学到了 save 函数,它不仅可以创建文档,而且能够修改文档。注意 save 函数修改文档其实是整体替换,而非对某个字段进行修改。在 PyMongo 中集合对象同样有 save 方法,且功能相同。
不过此方法不再推荐使用。如果要插入一条数据,就使用 insert_one 方法;如果要替换一条数据,就使用 replace_one 方法。替换文档的操作是针对 ObjectId 对象而言,也就是文档的 _id 字段的值。
举例说明,我们要替换 name 为 'Linux 基础入门' 的文档,也就是修改 _id 字段值为 ObjectId('5e4cc6bdf9df85a354b867d3') 的文档。
首先,需要引入 ObjectId 类:
In [44]: from bson.objectid import ObjectId
然后使用 replace_one 执行替换操作:
In [49]: list(course.find())
Out[49]:
[{'_id': ObjectId('5e4cc6bdf9df85a354b867d3'),
'author': 'James',
'name': 'Linux 基础入门',
'students_count': 1000},
{'_id': ObjectId('5e4cc6bdf9df85a354b867d4'),
'author': 'Wade',
'name': 'Python 简明教程',
'students_count': 2234},
{'_id': ObjectId('5e4cc6bdf9df85a354b867d5'),
'author': 'Wade',
'name': 'Git 与 GitHub 入门实践',
'students_count': 8777}]
In [50]: course.replace_one(
...: {'_id': ObjectId('5e4cc6bdf9df85a354b867d3')},
...: {'作者': 'James',
...: '课程名': 'Python 网络编程',
...: '学生数量': 123
...: }
...: )
Out[50]: <pymongo.results.UpdateResult at 0x7fac86574548>
In [51]: list(course.find())
Out[51]:
[{'_id': ObjectId('5e4cc6bdf9df85a354b867d3'),
'作者': 'James',
'学生数量': 123,
'课程名': 'Python 网络编程'},
{'_id': ObjectId('5e4cc6bdf9df85a354b867d4'),
'author': 'Wade',
'name': 'Python 简明教程',
'students_count': 2234},
{'_id': ObjectId('5e4cc6bdf9df85a354b867d5'),
'author': 'Wade',
'name': 'Git 与 GitHub 入门实践',
'students_count': 8777}]
如上所示,它与 update_one 方法的调用方式几乎一致。
删除数据
在 MongoDB 客户端中,可以使用 deleteOne 和 deleteMany 函数删除文档。在 Python 中也有对应的方法 delete_one 和 delete_many 删除一条或多条文档。参数也是一样的,用于提供过滤条件。
首先创建测试数据,创建多条具有相同键值对的文档:
In [52]: list(course.find())
Out[52]:
[{'_id': ObjectId('5e4cc6bdf9df85a354b867d3'),
'作者': 'James',
'学生数量': 123,
'课程名': 'Python 网络编程'},
{'_id': ObjectId('5e4cc6bdf9df85a354b867d4'),
'author': 'Wade',
'name': 'Python 简明教程',
'students_count': 2234},
{'_id': ObjectId('5e4cc6bdf9df85a354b867d5'),
'author': 'Wade',
'name': 'Git 与 GitHub 入门实践',
'students_count': 8777}]
In [53]: for i in range(4):
...: course.insert_one({'name': 'Test'})
...:
In [54]: list(course.find())
Out[54]:
[{'_id': ObjectId('5e4cc6bdf9df85a354b867d3'),
'作者': 'James',
'学生数量': 123,
'课程名': 'Python 网络编程'},
{'_id': ObjectId('5e4cc6bdf9df85a354b867d4'),
'author': 'Wade',
'name': 'Python 简明教程',
'students_count': 2234},
{'_id': ObjectId('5e4cc6bdf9df85a354b867d5'),
'author': 'Wade',
'name': 'Git 与 GitHub 入门实践',
'students_count': 8777},
{'_id': ObjectId('5e4cd7c9f9df85a354b867d7'), 'name': 'Test'},
{'_id': ObjectId('5e4cd7c9f9df85a354b867d8'), 'name': 'Test'},
{'_id': ObjectId('5e4cd7c9f9df85a354b867d9'), 'name': 'Test'},
{'_id': ObjectId('5e4cd7c9f9df85a354b867da'), 'name': 'Test'}]
使用 delete_one 方法删除一条数据:
In [55]: course.delete_one({'name': 'Test'})
Out[55]: <pymongo.results.DeleteResult at 0x7fac86439a48>
In [56]: list(course.find())
Out[56]:
[{'_id': ObjectId('5e4cc6bdf9df85a354b867d3'),
'作者': 'James',
'学生数量': 123,
'课程名': 'Python 网络编程'},
{'_id': ObjectId('5e4cc6bdf9df85a354b867d4'),
'author': 'Wade',
'name': 'Python 简明教程',
'students_count': 2234},
{'_id': ObjectId('5e4cc6bdf9df85a354b867d5'),
'author': 'Wade',
'name': 'Git 与 GitHub 入门实践',
'students_count': 8777},
{'_id': ObjectId('5e4cd7c9f9df85a354b867d8'), 'name': 'Test'},
{'_id': ObjectId('5e4cd7c9f9df85a354b867d9'), 'name': 'Test'},
{'_id': ObjectId('5e4cd7c9f9df85a354b867da'), 'name': 'Test'}]
使用 delete_many 删除全部符合条件的文档:
In [57]: course.delete_many({'name': 'Test'})
Out[57]: <pymongo.results.DeleteResult at 0x7fac864c1448>
In [58]: list(course.find())
Out[58]:
[{'_id': ObjectId('5e4cc6bdf9df85a354b867d3'),
'作者': 'James',
'学生数量': 123,
'课程名': 'Python 网络编程'},
{'_id': ObjectId('5e4cc6bdf9df85a354b867d4'),
'author': 'Wade',
'name': 'Python 简明教程',
'students_count': 2234},
{'_id': ObjectId('5e4cc6bdf9df85a354b867d5'),
'author': 'Wade',
'name': 'Git 与 GitHub 入门实践',
'students_count': 8777}]
修改集合名
在 PyMongo 中我们可以使用集合的 name 属性查看集合的名字,course 对象实际上就是 db.course 集合,是 learn 数据库中的 course 集合:
In [59]: db.course == course
Out[59]: True
# 集合的 full_name 属性值为用点号连接的数据库名和集合名的字符串
In [60]: db.course.full_name
Out[60]: 'learn.course'
In [61]: db.course.name
Out[61]: 'course'
In [62]: course.name
Out[62]: 'course'
集合对象的 rename 方法可以修改集合名,将 course 更名为 courses :
In [63]: db.list_collection_names()
Out[63]: ['course']
In [64]: db.course.rename('courses')
Out[64]: {'ok': 1.0}
In [65]: db.list_collection_names()
Out[65]: ['courses']
In [66]: list(db.courses.find())
Out[66]:
[{'_id': ObjectId('5e4cc6bdf9df85a354b867d3'),
'作者': 'James',
'学生数量': 123,
'课程名': 'Python 网络编程'},
{'_id': ObjectId('5e4cc6bdf9df85a354b867d4'),
'author': 'Wade',
'name': 'Python 简明教程',
'students_count': 2234},
{'_id': ObjectId('5e4cc6bdf9df85a354b867d5'),
'author': 'Wade',
'name': 'Git 与 GitHub 入门实践',
'students_count': 8777}]
挑战:向数据库中添加数据
打开挑战环境,执行如下命令下载文件:
$ cd ~/Code
$ wget https://labfile.oss.aliyuncs.com/courses/1364/helloshiyanlou.json
$ wget https://labfile.oss.aliyuncs.com/courses/1364/helloworld.json
启动 MongoDB 服务:
$ sudo service mongodb start
在当前目录 /home/shiyanlou/Code 下创建 Python 文件 insert_data.py :
$ touch insert_data.py
将代码写入其中,实现向 MongoDB 数据库 challenge 的 file 集合中写入文件中的数据,也就是刚刚下载的两个 JSON 文件。
最后执行程序:
$ python3 insert_data.py
# File Name: insert_data.py
import json
import os
from pymongo import MongoClient
json_data_list = []
file_name_list = os.listdir('/home/shiyanlou/Code')
for file_name in file_name_list:
if file_name.endswith('.json'):
with open(file_name) as f:
json_data_list.append(json.load(f))
client = MongoClient(host='localhost', port=27017)
db = client.challenge
db.file.insert_many(json_data_list)
网友评论