Motor Documentation

repository·master·Indexed 25 days ago

https://github.com/mongodb/motor

Motor 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.

Tokens
27.9K
Snippets
61
Records
170
Agent score
81%

What's inside Motor

  1. What is Motor?

    master
    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.
  2. Motor GridFS Classes for Tornado

    master

    The motor.motor_tornado module 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.
  3. Execute Mixed Bulk Write Operations

    master

    Motor supports executing a batch of different write operations (insert, update, remove) together using the bulk_write() method. You can control the execution order using the ordered parameter.

    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 a pymongo.errors.BulkWriteError.

    The BulkWriteError.details attribute provides the results of the operations that succeeded before the failure, along with details about the error.

    Unordered Bulk Write Operations

    When ordered=False is passed to bulk_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)
  4. How Motor wraps PyMongo methods

    master

    Motor achieves asynchronicity by wrapping synchronous PyMongo methods in a way that prevents blocking the event loop.

    The Wrapping Process

    1. Agnostic Declaration: For every PyMongo class, Motor defines an equivalent Agnostic class (e.g., AgnosticClient for MongoClient).
    2. Attribute Factories: Methods and properties in these agnostic classes are declared as MotorAttributeFactory types (e.g., an AsyncCommand).
    3. Implementation: At import time, create_class_with_framework calls create_attribute on these factories. This generates framework-specific wrappers for the target client (like AsyncIOMotorClient).

    Asynchronous Execution Model

    When an asynchronous method (like drop_database) is called, the Motor wrapper:

    1. Obtains a reference to the framework's event loop.
    2. Starts the synchronous PyMongo method on a thread within a global ThreadPoolExecutor.
    3. Creates a Future that will be resolved by the event loop once the thread completes.
    4. Returns the Future to the caller, allowing the user to await the result without blocking the event loop.
  5. Handle Thread Safety in Monitoring Callbacks

    master

    Important: 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 logging module is thread-safe and can be used directly within listeners without extra precautions.

  6. Configure Automatic Decryption without Automatic Encryption

    master

    While 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=True in your AutoEncryptionOpts object when initializing the AsyncIOMotorClient.

  7. Model Document Types with _id using NotRequired

    master

    When using TypedDict to model documents, you have three ways to handle the _id field which Motor adds automatically:

    1. Omit _id: The field is inserted automatically and available at runtime, but accessing it in code causes a type-checking error.
    2. Explicit _id: Define _id in your TypedDict. You must then provide an _id value manually every time you create an instance for insertion.
    3. Use typing.NotRequired: (Recommended for Python 3.11+ or using typing_extensions) This allows you to define _id as an optional field. It provides the flexibility of option 1 but allows you to access the _id field without type-checking errors.

    Note: For Python < 3.11, use the typing_extensions package for NotRequired.

  8. Best practice: Reuse the `AsyncIOMotorClient`

    master

    When 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 AsyncIOMotorClient once 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.

  9. Understand the Motor Object Hierarchy

    master

    Motor follows a 4-level object hierarchy similar to PyMongo:

    1. MotorClient: Represents a mongod process or a cluster. You create this once and use it for the lifetime of your application.
    2. MotorDatabase: Represents a specific database within a mongod instance. Accessed from a client.
    3. MotorCollection: Represents a collection of documents within a database. Accessed from a database.
    4. MotorCursor: Represents the set of documents matching a query, returned by executing .find() on a MotorCollection.
  10. Motor requirements and dependencies

    master

    Motor is a non-blocking MongoDB driver for asyncio and Tornado applications.

    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 Tornado or asyncio. For detailed compatibility information, see the requirements documentation.