Motor 提供了一个基于协程的 API,用于从Tornado或asyncio对 MongoDB 的非阻塞访问。Motor 在连接到 MongoDB 或执行 I/O 时从不阻塞事件循环。Motor 封装了几乎所有 PyMongo 的 API 并使其成为非阻塞的。
Motor 和 PyMongo 一样,表示具有 4 级对象层次结构的数据:
- AsyncIOMotorClient 代表一个mongod进程,或者它们的一个集群。您显式创建这些客户端对象之一,将其连接到正在运行的 mongod,并在应用程序的整个生命周期中使用它。
- AsyncIOMotorDatabase:每个 mongod 都有一组数据库(磁盘上不同的数据文件集)。您可以从客户端获取对数据库的引用。
- AsyncIOMotorCollection:一个数据库有一组集合,其中包含文档;您从数据库中获得对集合的引用。
- AsyncIOMotorCursor:find()在AsyncIOMotorCollection上得到一个AsyncIOMotorCursor,它表示匹配查询的文档集。
一、安装:
python3 -m pip install motor
motor2.2 版本要求:
- python >= 3.5
- Pymongo >= 3.12
二、使用:
1、创建客户端
AsyncIOMotorClient您通常会在应用程序启动时创建单个实例
import motor.motor_asyncio client = motor.motor_asyncio.AsyncIOMotorClient()
这将连接到mongod默认主机和端口上的侦听。您可以指定主机和端口,例如:
client = motor.motor_asyncio.AsyncIOMotorClient('localhost', 27017)
Motor 还支持连接 URI:
client = motor.motor_asyncio.AsyncIOMotorClient('mongodb://localhost:27017')
连接到集合,例如:
client = motor.motor_asyncio.AsyncIOMotorClient('mongodb://host1,host2/?replicaSet=my-replicaset-name')
2、获取数据库
一个 MongoDB 实例可以支持多个独立的数据库。从一个开放的客户端,您可以使用点表示法或括号表示法获得对特定数据库的引用:
db = client.test_database 或 db = client['test_database']
创建对数据库的引用没有 I/O,也不需要 await表达式。
3、获取集合
集合是存储在 MongoDB 中的一组 文档,可以认为大致相当于关系数据库中的表。在 Motor 中获取集合与获取数据库相同:
collection = db.test_collection 或 collection = db['test_collection']
就像获取对数据库的引用一样,获取对集合的引用不需要 I/O,也不需要await表达式。
4、插入文档
4.1 插入单条数据insert_one(),要在 MongoDB 中存储文档,请调用insert_one()表达式 await:
async def do_insert(): document = {'key': 'value'} result = await db.test_collection.insert_one(document) print('result %s' % repr(result.inserted_id))
import asyncio loop = asyncio.get_event_loop() loop.run_until_complete(do_insert()) result ObjectId('...')
4.2 大批量插入文档insert_many():
async def do_insert(): result = await db.test_collection.insert_many( [{'i': i} for i in range(2000)]) print('inserted %d docs' % (len(result.inserted_ids),)) loop = asyncio.get_event_loop() loop.run_until_complete(do_insert())
4.3 使用find_one获取单个文档,用于find_one()获取与查询匹配的第一个文档。例如,要获取键“i”的值小于 1 的文档:
async def do_find_one(): document = await db.test_collection.find_one({'i': {'$lt': 1}}) pprint.pprint(document) loop = asyncio.get_event_loop() loop.run_until_complete(do_find_one())
4.4 查询多个文档,用于find()查询一组文档。 find()没有 I/O,也不需要await 表达式。它只是创建一个AsyncIOMotorCursor实例。当您调用to_list() 或执行循环时,查询实际上是在服务器上执行的。
查找“i”小于 5 的所有文档:
async def do_find(): cursor = db.test_collection.find({'i': {'$lt': 5}}).sort('i') for document in await cursor.to_list(length=100): pprint.pprint(document) loop = asyncio.get_event_loop() loop.run_until_complete(do_find())
当您调用to_list以防止 Motor 缓冲无限数量的文档时,需要一个参数 length。
您可以在循环中一次处理一个文档:async for
async def do_find(): c = db.test_collection async for document in c.find({'i': {'$lt': 2}}): pprint.pprint(document) loop = asyncio.get_event_loop() loop.run_until_complete(do_find())
在开始迭代之前,您可以对查询进行sort、limit或skip:
async def do_find(): cursor = db.test_collection.find({'i': {'$lt': 4}}) # Modify the query before iterating cursor.sort('i', -1).skip(1).limit(2) async for document in cursor: pprint.pprint(document) loop = asyncio.get_event_loop() loop.run_until_complete(do_find())
游标实际上并不单独从服务器检索每个文档;它可以有效地大批量获取文档。
4.5 获取文档数,用于count_documents()确定集合中的文档数,或与查询匹配的文档数:
async def do_count(): n = await db.test_collection.count_documents({}) print('%s documents in collection' % n) n = await db.test_collection.count_documents({'i': {'$gt': 1000}}) print('%s documents where i > 1000' % n) loop = asyncio.get_event_loop() loop.run_until_complete(do_count())
4.6 更新文档
4.6.1 单个文档全部更新:replace_one(),它需要两个参数:一个指定要替换哪个文档的查询和一个替换文档。该查询遵循与find_one()相同的语法。替换文档:
async def do_replace(): coll = db.test_collection old_document = await coll.find_one({'i': 50}) print('found document: %s' % pprint.pformat(old_document)) _id = old_document['_id'] result = await coll.replace_one({'_id': _id}, {'key': 'value'}) print('replaced %s document' % result.modified_count) new_document = await coll.find_one({'_id': _id}) print('document is now %s' % pprint.pformat(new_document)) loop = asyncio.get_event_loop() loop.run_until_complete(do_replace())
您可以看到replace_one()它用新文档替换了旧文档中的所有的内容。
4.6.2 单个文档部分更新:update_one(),与 MongoDB 的修饰符运算符一起使用update_one()来更新文档的一部分并保持其余部分不变。
我们将找到“i”为 51 的文档,并使用$set 运算符将“key”设置为“value”:
async def do_update(): coll = db.test_collection result = await coll.update_one({'i': 51}, {'$set': {'key': 'value'}}) print('updated %s document' % result.modified_count) new_document = await coll.find_one({'i': 51}) print('document is now %s' % pprint.pformat(new_document)) loop = asyncio.get_event_loop() loop.run_until_complete(do_update())
“key”设置为“value”,“i”仍然是 51。
4.6.3 更新全部文档:update_many(),您可以使用以下命令更新所有文档:
await coll.update_many({'i': {'$gt': 100}}, {'$set': {'key': 'value'}})
也可以看看 MongoDB 文档 更新
4.7 删除文档: delete_many(),删除所有匹配的文档。
async def do_delete_many(): coll = db.test_collection n = await coll.count_documents({}) print('%s documents before calling delete_many()' % n) result = await db.test_collection.delete_many({'i': {'$gte': 1000}}) print('%s documents after' % (await coll.count_documents({}))) loop = asyncio.get_event_loop() loop.run_until_complete(do_delete_many())