Mongomotor - асинхронный драйвер MongoDb

Motor presents a coroutine-based API for non-blocking access to MongoDB from [tornado] or [asyncio].

$ python -m pip install motor

Разница между pymongo и mongomotor

Фичи

  • Неблокирующий асинхронный драйвер для MongoDB. Его можно использовать из приложений Tornado или asyncio. Motor никогда не блокирует цикл обработки событий при подключении к MongoDB или выполнении операций ввода-вывода.
  • Motor охватывает почти весь API PyMongo и делает его неблокирующим.
  • Модуль tornado.gen позволяет использовать сопрограммы для упрощения асинхронного кода. Методы motor возвращают фьючерсы, которые удобно использовать с сопрограммами.
  • Настраиваемые циклы ввода/вывода. Motor поддерживает приложения Tornado с несколькими файлами IOLoops. Передайте io_loop аргумент, чтобы настроить цикл для экземпляра MotorClient.
  • Потоковая передача статических файлов из GridFS. Motor может передавать данные из GridFS в Tornado RequestHandler с помощью класса stream_to_handler() или GridFSHandler. Он также может обслуживать данные GridFS с помощью [aiohttp], используя AIOHTTPGridFSкласс.

Tutorial: Using Motor With Tornado

Tutorial: Using Motor With asyncio

Motor, как и PyMongo, представляет данные с 4-уровневой иерархией объектов:

  • AsyncIOMotorClient представляет процесс mongod или гуппу процессов. Вы явно создаете один из этих клиентских объектов, подключаете его к работающему mongod или mongods и используете его на протяжении всего времени существования вашего приложения.
  • AsyncIOMotorDatabase каждый mongod имеет набор баз данных (отдельные наборы файлов данных на диске). Вы можете получить ссылку на базу данных от клиента.
  • AsyncIOMotorCollection в базе данных есть набор коллекций, содержащих документы; вы получаете ссылку на коллекцию из базы данных.
  • AsyncIOMotorCursor выполнение find() для AsyncIOMotorCollection получает AsyncIOMotorCursor, представляющий набор документов, соответствующих запросу.

  • Создание клиента
  • получение бд
  • получение коллекции
import motor.motor_asyncio

client = motor.motor_asyncio.AsyncIOMotorClient()
db = client.test_database
collection = db.test_collection

Добавление документов

>>> 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 = client.get_io_loop()
>>> loop.run_until_complete(do_insert())
result ObjectId('...')

Find one

>>> async def do_find_one():
...    document = await db.test_collection.find_one({'i': {'$lt': 1}})
...    pprint.pprint(document)

>>> loop = client.get_io_loop()
>>> loop.run_until_complete(do_find_one())
{'_id': ObjectId('...'), 'i': 0}

Используйте find() для запроса набора документов. find() не выполняет ввод-вывод и не требует выражения await. Он просто создает экземпляр AsyncIOMotorCursor. Запрос фактически выполняется на сервере, когда вы вызываете to_list() или выполняете асинхронный цикл for.

>>> 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 = client.get_io_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}

Вы можете обрабатывать один документ за раз в асинхронном цикле for. Вы можете применить сортировку, ограничение или пропустить запрос, прежде чем начать итерацию.

>>> async def do_find():
...     c = db.test_collection
...     # Modify the query before iterating
...     cursor.sort('i', -1).skip(1).limit(2)
...     async for document in cursor:
...         pprint.pprint(document)

>>> loop = client.get_io_loop()
>>> loop.run_until_complete(do_find())
{'_id': ObjectId('...'), 'i': 2}
{'_id': ObjectId('...'), 'i': 1}

Подсчет документов

>>> async def do_count():
...     n = await db.test_collection.count_documents({})
...     print('%s documents in collection' % n)
...     # matched to pattern
...     n = await db.test_collection.count_documents({'i': {'$gt': 1000}})
...     print('%s documents where i > 1000' % n)

>>> loop = client.get_io_loop()
>>> loop.run_until_complete(do_count())
2000 documents in collection
999 documents where i > 1000

Updating documents

replace_one() изменяет документ. Для этого требуются два параметра: запрос, указывающий, какой документ следует заменить, и замещающий документ. Запрос следует тому же синтаксису, что и для find() или find_one(). replace_one() заменяет все в старом документе, кроме его _id, новым документом.

Используйте update_one() с операторами-модификаторами MongoDB, чтобы обновить часть документа и оставить остальную часть нетронутой. update_one() афектит только первый найденный документ. Чтобы изменить несколько - надо использовать update_many()

>>> 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 = client.get_io_loop()
>>> loop.run_until_complete(do_replace())
found document: {'_id': ObjectId('...'), 'i': 50}
replaced 1 document
document is now {'_id': ObjectId('...'), '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 = client.get_io_loop()
>>> loop.run_until_complete(do_update())
updated 1 document
document is now {'_id': ObjectId('...'), 'i': 51, 'key': 'value'}

Deleting documents

delete_one() и delete_many(). Оба метода используют тот же синтаксис, что и find_one().

>>> async def do_delete_one():
...     coll = db.test_collection
...     n = await coll.count_documents({})
...     print('%s documents before calling delete_one()' % n)
...     result = await db.test_collection.delete_one({'i': {'$gte': 1000}})
...     print('%s documents after' % (await coll.count_documents({})))

>>> loop = client.get_io_loop()
>>> loop.run_until_complete(do_delete_one())
2000 documents before calling delete_one()
1999 documents after

>>> 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 = client.get_io_loop()
>>> loop.run_until_complete(do_delete_many())
1999 documents before calling delete_many()
1000 documents after

Примеры использования mongomotor

API

Pymongo references:

[fastapi] with motor and some questions

Смотри еще: