Motor Documentation
repository·master·Indexed 25 days ago
https://github.com/mongodb/motorMotor is a full-featured, non-blocking MongoDB driver for Python designed for asyncio and Tornado applications, providing a coroutine-based API for asynchronous access to MongoDB. As of May 14th, 2025, Motor is deprecated in favor of the PyMongo Async API. It supports Python 3.10+ and PyMongo >=4.9, <5, with optional dependencies for GSSAPI, AWS authentication, SRV URIs, OCSP, Snappy, Zstandard compression, and Client-Side Field Level Encryption.
What's inside Motor
- Motor is an asynchronous Python driver for MongoDB. It provides a coroutine-based API that allows for non-blocking access to MongoDB from either Tornado or asyncio frameworks. It is designed for high-throughput environments where efficient use of CPU and hardware capacity is required.
Use Motor with Tornado
masterThis documentation section covers the integration of Motor with the Tornado web framework. For generalasynciointegration (not specific to Tornado), refer to theapi-asynciodocumentation.Motor GridFS Classes for Tornado
masterThe
motor.motor_tornadomodule provides asynchronous classes for interacting with GridFS, which is used to store and retrieve large blobs of data in MongoDB.The following classes are available for managing GridFS operations in a Tornado environment:
MotorGridFSBucket: The main interface for managing GridFS buckets.MotorGridIn: Used for writing data to GridFS.MotorGridOut: Used for reading data from GridFS.MotorGridOutCursor: An asynchronous cursor for iterating over GridFS data.
Execute Mixed Bulk Write Operations
masterMotor supports executing a batch of different write operations (insert, update, remove) together using the
bulk_write()method. You can control the execution order using theorderedparameter.Ordered Bulk Write Operations
By default (or when
ordered=True), operations are executed serially in the order provided. If a write failure occurs (e.g., a duplicate key error), the remaining operations in the batch are aborted, and Motor raises apymongo.errors.BulkWriteError.The
BulkWriteError.detailsattribute provides the results of the operations that succeeded before the failure, along with details about the error.Unordered Bulk Write Operations
When
ordered=Falseis passed tobulk_write(), operations are sent to the server in an arbitrary order and may be executed in parallel. In this mode, errors do not stop the execution of other operations; instead, all errors are reported after all operations in the batch have been attempted.from pymongo import InsertOne, DeleteOne, ReplaceOne from pymongo.errors import BulkWriteError # Example of Ordered Bulk Write (default) async def ordered_example(): requests = [ ReplaceOne({"j": 2}, {"i": 5}), InsertOne({"_id": 4}), # This might fail DeleteOne({"i": 5}), ] try: await db.test.bulk_write(requests) except BulkWriteError as bwe: print(bwe.details) # Example of Unordered Bulk Write async def unordered_example(): requests = [ InsertOne({"_id": 1}), DeleteOne({"_id": 2}), InsertOne({"_id": 3}), ReplaceOne({"_id": 4}, {"i": 1}), ] try: await db.test.bulk_write(requests, ordered=False) except BulkWriteError as bwe: print(bwe.details)How Motor wraps PyMongo methods
masterMotor achieves asynchronicity by wrapping synchronous PyMongo methods in a way that prevents blocking the event loop.
The Wrapping Process
- Agnostic Declaration: For every PyMongo class, Motor defines an equivalent
Agnosticclass (e.g.,AgnosticClientforMongoClient). - Attribute Factories: Methods and properties in these agnostic classes are declared as
MotorAttributeFactorytypes (e.g., anAsyncCommand). - Implementation: At import time,
create_class_with_frameworkcallscreate_attributeon these factories. This generates framework-specific wrappers for the target client (likeAsyncIOMotorClient).
Asynchronous Execution Model
When an asynchronous method (like
drop_database) is called, the Motor wrapper:- Obtains a reference to the framework's event loop.
- Starts the synchronous PyMongo method on a thread within a global
ThreadPoolExecutor. - Creates a
Futurethat will be resolved by the event loop once the thread completes. - Returns the
Futureto the caller, allowing the user toawaitthe result without blocking the event loop.
- Agnostic Declaration: For every PyMongo class, Motor defines an equivalent
Handle Thread Safety in Monitoring Callbacks
masterImportant: Thread Safety Warning
Monitoring listener callbacks are executed on background threads, not the main thread.
If you need to interact with your application's event loop (Tornado or asyncio) from within a listener callback, you must defer the action to the main thread to ensure thread safety:
- For Tornado: Use
tornado.ioloop.IOLoop.current().add_callback(func). - For asyncio: Use
loop.call_soon_threadsafe(func).
Note: The standard Python
loggingmodule is thread-safe and can be used directly within listeners without extra precautions.- For Tornado: Use
Motor methods are coroutines
masterWhile Motor supports nearly every method available in PyMongo, any method that performs network I/O in Motor is a coroutine. You must useawaitto execute these operations.Configure Automatic Decryption without Automatic Encryption
masterWhile automatic encryption requires Enterprise or Atlas, automatic decryption is supported for all users (including Community edition).
To enable automatic decryption while performing encryption manually (explicitly), set
bypass_auto_encryption=Truein yourAutoEncryptionOptsobject when initializing theAsyncIOMotorClient.Model Document Types with _id using NotRequired
masterWhen using
TypedDictto model documents, you have three ways to handle the_idfield which Motor adds automatically:- Omit
_id: The field is inserted automatically and available at runtime, but accessing it in code causes a type-checking error. - Explicit
_id: Define_idin yourTypedDict. You must then provide an_idvalue manually every time you create an instance for insertion. - Use
typing.NotRequired: (Recommended for Python 3.11+ or usingtyping_extensions) This allows you to define_idas an optional field. It provides the flexibility of option 1 but allows you to access the_idfield without type-checking errors.
Note: For Python < 3.11, use the
typing_extensionspackage forNotRequired.- Omit
Best practice: Reuse the `AsyncIOMotorClient`
masterWhen building applications (e.g., web servers with
aiohttp), do not create a new client object for every request. This incurs a significant performance penalty because the client connects on demand during the first operation.Instead, create the
AsyncIOMotorClientonce when your application starts and reuse that single client instance for the entire lifetime of the process. A common pattern is to store a database handle from the client on your application object.Understand the Motor Object Hierarchy
masterMotor follows a 4-level object hierarchy similar to PyMongo:
MotorClient: Represents amongodprocess or a cluster. You create this once and use it for the lifetime of your application.MotorDatabase: Represents a specific database within amongodinstance. Accessed from a client.MotorCollection: Represents a collection of documents within a database. Accessed from a database.MotorCursor: Represents the set of documents matching a query, returned by executing.find()on aMotorCollection.
Motor requirements and dependencies
masterMotor is a non-blocking MongoDB driver for
asyncioandTornadoapplications.Core Requirements
- Python: 3.10+
- PyMongo: >=4.9, <5
- Operating Systems: Unix (including macOS) or Windows
Compatibility
Motor works in any environment officially supported by
Tornadoorasyncio. For detailed compatibility information, see the requirements documentation.