Mongomotor - асинхронный драйвер MongoDb
Теги: data-bases mongodb asyncio
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('...')
>>> 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
- Motor Tornado API
    
MotorClient– Connection to MongoDBMotorClientSession– Sequence of operationsMotorDatabaseMotorCollectionMotorChangeStreamMotorClientEncryptionMotorCursorMotorCommandCursor- Motor GridFS Classes
 motor.web- Integrate Motor with the [tornado] web framework
 - Motor asyncio API
    
- AsyncIOMotorClient – Connection to MongoDB
 - AsyncIOMotorClientSession – Sequence of operations
 - AsyncIOMotorDatabase some operations with given named db
 - AsyncIOMotorCollection
 AsyncIOMotorChangeStreamAsyncIOMotorClientEncryption- AsyncIOMotorCursor prowide query filtering
 AsyncIOMotorCommandCursor- asyncio GridFS Classes
 motor.aiohttp- Integrate Motor with the [aiohttp] web framework
 
Pymongo references:
- mongo_client – Tools for connecting to MongoDB
 - client_session – Logical sessions for sequential operations
 - pynongo collection
 - operations – Operation class definitions, в т.ч. IndexModel
 - results – Result class definitions
 - errorrs Exceptions raised by the pymongo package
 
[fastapi] with motor and some questions
- Getting Started with MongoDB and FastAPI. Репо с примером
 - Building a CRUD App with FastAPI and MongoDB
 - How to parse ObjectId in a pydantic model?
 - Why does PyMongo add an _id field to all of my documents? in a FAQ
 - Datetimes and Timezones in pymongo
 
Смотри еще:
- документация
 - на github
 - on mongo world
 - [mongodb]
 - [mongoengine]
 - [tornado]
 - [mongo-solutions] Вопросы и решения по mongo