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())
