Motor使用教程

Motor提供了一個基於協程的API,用於對MongoDB的非阻塞訪問。python

譯者:桑葚ICEmongodb

安裝

python3 -m pip install motor
複製代碼

建立客戶端

指定主機和端口號
import motor.motor_asyncio
client = motor.motor_asyncio.AsyncIOMotorClient('localhost', 27017)
複製代碼
使用用戶名和密碼
motor.motor_asyncio.AsyncIOMotorClient('mongodb://root:123456@localhost:27017')
複製代碼

獲取數據庫

MongoDB的單個實例能夠支持多個獨立的數據庫。在開放式客戶端中,您可使用點表示法或括號表示法來獲取對特定數據庫的引用:數據庫

db = client.test_database
db = client['test_database']
複製代碼

建立對數據庫的引用不會執行I / O,也不須要 await 表達式。服務器

獲取集合

一個集合是一組存儲在MongoDB中的文檔,而且能夠被認爲是大體在關係數據庫中的表的當量。獲取Motor中的集合與獲取數據庫的工做方式相同:異步

collection = db.test_collection
collection = db['test_collection']
複製代碼

就像獲取對數據庫的引用同樣,獲取對集合的引用不會產生I / O而且不須要 await 表達式。async

插入文檔(insert_one)

與PyMongo同樣,Motor使用Python字典表示MongoDB文檔。要存儲在MongoDB中的文檔,在 await 表達式中調用 insert_one()oop

async def do_insert():
    document = {'key': 'value'}
    result = await db.test_collection.insert_one(document)  # insert_one只能插入一條數據
    print('result %s' % repr(result.inserted_id))

loop = asyncio.get_event_loop()
loop.run_until_complete(do_insert())
# result ObjectId('...')
複製代碼

批量插入文檔(insert_many)

async def do_insert():
    result = await db.test_collection.insert_many(
        [{'i': i} for i in range(2000)])  # insert_many能夠插入一條或多條數據,可是必須以列表(list)的形式組織數據
    print('inserted %d docs' % (len(result.inserted_ids),))

loop = asyncio.get_event_loop()
loop.run_until_complete(do_insert())
# inserted 2000 docs
複製代碼

查詢一個文檔(find_one)

使用 find_one() 獲得匹配查詢的第一個文檔。例如,要獲取密鑰「i」的值小於1的文檔:post

async def do_find_one():
    document = await db.test_collection.find_one({'i': {'$lt': 1}})  # find_one只能查詢一條數據
    pprint.pprint(document)

loop = asyncio.get_event_loop()
loop.run_until_complete(do_find_one())
# {'_id': ObjectId('...'), 'i': 0}
複製代碼

注意:結果是一個字典匹配咱們以前插入的字典。spa

查詢多個文檔(find)

使用 find() 要查詢的一組文檔。 find() 沒有I / O,也不須要 await 表達式。它只是建立一個 AsyncIOMotorCursor 實例。當您調用 to_list() 或爲循環執行異步時 (async for) ,查詢其實是在服務器上執行的。code

查詢 「 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())
# {'_id': ObjectId('...'), 'i': 0}
# {'_id': ObjectId('...'), 'i': 1}
# {'_id': ObjectId('...'), 'i': 2}
# {'_id': ObjectId('...'), 'i': 3}
# {'_id': ObjectId('...'), 'i': 4}
複製代碼

一length ,調用方法 to_list 的必傳參數,防止 Motor 從緩衝中獲取的文檔數量不受限制,此處限制爲100。

使用 async for 查詢全部文檔

您能夠在循環中一次處理一個文檔:async for

async def do_find():
    c = db.test_collection
    async for document in c.find({}):  # 查詢全部文檔
        pprint.pprint(document)

loop = asyncio.get_event_loop()
loop.run_until_complete(do_find())
# {'_id': ObjectId('...'), 'i': 0}
# {'_id': ObjectId('...'), 'i': 1}
複製代碼

您能夠在開始迭代以前對查詢應用排序,跳過或限制:

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)  # 對查詢應用排序(sort),跳過(skip)或限制(limit)
    async for document in cursor:
        pprint.pprint(document)

loop = asyncio.get_event_loop()
loop.run_until_complete(do_find())
# {'_id': ObjectId('...'), 'i': 2}
# {'_id': ObjectId('...'), 'i': 1}
複製代碼

遊標 (cursor) 實際上並非單獨從服務器檢索每一個文檔; 它能夠大批量地獲取文檔。

使用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())
# 2000 documents in collection
# 999 documents where i > 1000
複製代碼

更新文檔(推薦使用update_one或update_many)

replace_one() 更改文檔。它須要兩個參數:一個指定要替換哪一個文檔的查詢和一個替換文檔。該查詢遵循與 find() 或 相同的語法 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']

    old_document['i'] = -1  # 修改文檔(dict)的key, value
    old_document['new'] = 'new'  # 增長文檔(dict)的key, value
    del old_document['i']  # 刪除文檔(dict)的key, value

    result = await coll.replace_one(
        {'_id': _id}, old_document)  # replace_one第一個參數爲查詢條件, 第二個參數爲更新後的文檔
    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())
# found document: {'_id': ObjectId('...'), 'i': 50}
# replaced 1 document
# document is now {'_id': ObjectId('...'), 'key': 'value'}
複製代碼

除了 _id 不變,replace_one() 會對修改後文檔的全部字段作更新操做, 慎用

update_one() 與MongoDB的修飾符運算符一塊兒使用來更新文檔的一部分並保持其他部分不變。咱們將找到「i」爲51的文檔,並使用 $set 運算符將「key」設置爲「value」:

async def do_update():
    coll = db.test_collection
    result = await coll.update_one({'i': 51}, {'$set': {'key': 'value'}})  # 僅新增或更改該文檔的某個key
    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())
# updated 1 document
# document is now {'_id': ObjectId('...'), 'i': 51, 'key': 'value'}
複製代碼

「key」設置爲「value」,「i」仍爲51。

update_one() 隻影響它找到的第一個文檔,您可使用 update_many() 更新全部文檔:

await coll.update_many({'i': {'$gt': 100}}, {'$set': {'key': 'value'}})
複製代碼

刪除文檔

delete_many() 採用與語法相同的 find() 查詢。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())
# 2000 documents before calling delete_many()
# 1000 documents after
複製代碼

Commands

MongoDB上的全部操做都在內部實現爲命令。

使用如下 command() 方法 運行它們 AsyncIOMotorDatabase

from bson import SON

async def use_distinct_command():
    response = await db.command(SON([("distinct", "test_collection"),
                                     ("key", "i")]))

loop = asyncio.get_event_loop()
loop.run_until_complete(use_distinct_command())
複製代碼

因爲命令參數的順序很重要,所以不要使用Python dict來傳遞命令的參數。相反,養成使用PyMongo附帶bson.SON的 bson 模塊的習慣。

許多命令都有特殊的輔助方法,例如 create_collection() or aggregate() ,但這些方便的命令基於 command() 方法。

推薦閱讀:官方文檔, MongoDB的基本概念和操做

相關文章
相關標籤/搜索