最近在学习 python 的数据库存储,PyMongo 是 MongoDB 官方推荐的 python 数据库,因此想要将学习内容整理一下。
在此之前,请确保已经安装了 python 和 MongoDB。
python 的下载地址:
https://www.python.org/downloads/
MongoDB 的安装方法:
http://api.mongodb.com/python/current/installation.html
另外,MongoDB 官方推出了 MongoDB 的可视化工具 MongoDB Compass:
https://www.mongodb.com/download-center/compass?jmp=docs
下面直接进入正题
连接 Mongo 客户端
开始之前,首先要在 python shell 中导入 pymongo,并且在默认主机和默认端口运行一个 MongoDB 实例
#在 python shell 下导入 pymongo
>>> import pymongo
在命令行模式下启动 MongoDB
>>> mongod
出现提示在 27017 端口等待连接就启动成功了
连接的第一步就是创建一个运行 mongod 实例的 mongo 客户端 ,创建客户端可以明确指定主机和端口,也可以直接使用默认主机和端口。
>>> from pymongo import MongoClient
#使用默认主机和端口
>>> client = MongoClient()
#使用指定主机和端口的方法创建客户端实例
>>> client = MongoClient('localhost', 27017)
#使用 MongoDB NRI 格式指定主机和端口的方法创建客户端实例
>>> client = MongoClient('mongodb://localhost:27017/')
创建后 mongo 服务器端就会提示连接主机和端口表示连接成功。
存储数据
一个 mongoDB 的实例可以有多个独立的数据库,你可以用属性和字典两种不同的风格访问数据库
#以属性风格访问(attribute style access)
>>> db = client.test_database
#以字典风格访问(dictionary style access)
>>> db = client['test-database']
数据库创建成功后,就要在数据库中创建集合。集合是存储在 MongoDB 中的一组文件,你可以将集合近似看成关系型数据库中的表。同样可以使用两种方式创建集合。
#using attribute style access
>>> collection = db.test_collection
#using dictionary style access
>>> collection = db['test-collection']
注意:上面的创建数据库和集合命令并没有实际操作 MongoDB 服务器,只有当加入了文件才是真正创建了数据库和集合。
所以以上两个操作 MongoDB 服务器并不会有什么响应。
MongoDB 中的数据是以 JSON 风格的文件存储的,在 PyMongo 中使用字典来表示文件
>>> post = {"author": "Mike",
... "text": "My first blog post!",
... "tags": ["mongodb", "python", "pymongo"]}
接下来就可以使用 insert_one() 方法将文件存入到集合
>>> post_id = collection.insert_one(post)
这时 MongoDB 服务器就提示 received client metadata from 主机:端口,就表示一个数据文件已经存入到 MongoDB 服务器中。
并且这个文件会自动加上一个在这个集合中唯一的 "_id" 值,insert_one() 返回一个 InsertOneResult 的实例。
集合中加入文件后于是这个集合和数据库就在服务器中创建了,可以用 数据库.collection_names() 方法和 客户端.database_names() 方法查看某个数据库中有哪些集合以及某个客户拥有哪些数据库。
可以看出,MongoDB 是以集合来存储数据的,客户端,数据库,集合的结构关系大致是这样的:
数据查询
find_one () 方法返回符合查询的单个文件,或者返回符合查询的多个文件的第一个文件。返回类型是字典
可以看到 "_id" 就是自动加入到这个文件的。
也可以在 find_one() 中加入索引条件
可以看到查到了刚刚存到 collection 集合中的文件。之所以和前面 find_one() 方法查询到的不一样,是因为我之前做实验的时候就在 collection 中插入了一个文件,find_one() 由于没有查询条件,就自动查询到 collection 集合中的第一个文件。
值得注意的是,如果没有匹配到符合条件的文件,就返回 None,什么也不发生。
我们也可以通过 ObjectId 查询
>>> post_id
ObjectId(...)
>>> collection.find_one({"_id": post_id})
{u'_id': ObjectId('...'),
u'author': u'Mike',
u'date': datetime.datetime(...),
u'tags': [u'mongodb', u'python', u'pymongo'],
u'text': u'My first blog post!'}
也可以使用 insert_many() 方法。通过给他的第一个参数传入一个列表,就可以将列表中的每个文件插入到集合中。
>>> new_posts = [{"author": "Mike",
... "text": "Another post!",
... "tags": ["bulk", "insert"]},
... {"author": "Eliot",
... "title": "MongoDB is fun",
... "text": "and pretty easy too!"}]
使用 insert_many() 方法插入列表中的多个文件。
可以看到 insert_many() 返回一个 InsertManyResult 实例,并且插入的每个文件都有各自的 "_id" 值。
find() 方法可以获得查询匹配到的多个文件。他返回一个 Cursor 实例,这个实例允许我们在所有匹配到的文件上迭代。
和 find_one() 一样,可以给 find() 传递参数限定查询条件
count() 方法可以返回一次查询匹配的文件数。
因此可以查看一个集合中有多少个文件(documents)以及一次特定查询匹配的文件数。
MongoDB 支持多种类型的高级查询。可以指定特定范围内的查询,例如查询包含 tags 属性的文件
"$exists" 是一个范围查询的操作符。如果还有年龄属性的话,当然可以查询出年龄大于某个值或者小于某个值的那些文件(documents) 。另外还可以使用 sort() 方法对得到的结果进行排序。
更多的高级范围查询条件可以查阅:https://docs.mongodb.com/manual/reference/operator/query/
添加索引
添加索引可以加快特定的查询 ,还能给查询和存储文件添加一些其他的功能。
例如可以给键创建一个唯一索引,阻止那些和这个键对应的值相同的文件插入。
首先我们需要创建索引
可以看到现在有两个索引了,其中一个就是 "_id" 上的索引是 MongoDB 自动创建的,还有一个 "user_id" 上的索引就是我们创建的。
现在创建一些用户配置文件
>>> user_profiles = [
... {'user_id': 211, 'name': 'Luke'},
... {'user_id': 212, 'name': 'Ziltoid'}]
>>> result = db.profiles.insert_many(user_profiles)
索引现在阻止集合中和 "user_id" 值相同的文件的插入。
>>> new_profile = {'user_id': 213, 'name': 'Drew'}
>>> duplicate_profile = {'user_id': 212, 'name': 'Tommy'}
>>> result = db.profiles.insert_one(new_profile) # This is fine.
>>> result = db.profiles.insert_one(duplicate_profile)
Traceback (most recent call last):
DuplicateKeyError: E11000 duplicate key error index: test_database.profiles.$user_id_1 dup key: { : 212 }