diff --git a/source/includes/motor-comparison-table-pymongo.rst b/source/includes/motor-comparison-table-pymongo.rst
new file mode 100644
index 00000000..a9700e46
--- /dev/null
+++ b/source/includes/motor-comparison-table-pymongo.rst
@@ -0,0 +1,21 @@
+.. list-table::
+ :header-rows: 1
+ :class: compatibility-large
+
+ * - Motor Version
+ - {+driver-short+} Version
+
+ * - 3.7
+ - 4.10
+
+ * - 3.6
+ - 4.9
+
+ * - 3.3
+ - 4.4
+
+ * - 3.1
+ - 4.2
+
+ * - 3.0
+ - 4.0
\ No newline at end of file
diff --git a/source/reference/compatibility.txt b/source/reference/compatibility.txt
index 91d64e0c..2798a5a1 100644
--- a/source/reference/compatibility.txt
+++ b/source/reference/compatibility.txt
@@ -48,4 +48,13 @@ The following compatibility table specifies the recommended version of
{+driver-short+} for use with a specific version of Python.
The first column lists the driver version.
-.. include:: /includes/language-compatibility-table-pymongo.rst
\ No newline at end of file
+.. include:: /includes/language-compatibility-table-pymongo.rst
+
+.. _pymongo-motor-compatibility:
+
+Motor Compatibility
+-------------------
+
+The following table shows the equivalent versions of Motor and {+driver-short+}.
+
+.. include:: /includes/motor-comparison-table-pymongo.rst
diff --git a/source/reference/migration.txt b/source/reference/migration.txt
index febf2911..919739ef 100644
--- a/source/reference/migration.txt
+++ b/source/reference/migration.txt
@@ -28,9 +28,43 @@ library `__. In this guide, you can
identify the changes you must make to migrate an application from {+driver-short+} or
Motor to the {+driver-async+} driver.
+Synchronous Versus Asynchronous
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+To determine whether to migrate to the {+driver-async+} driver or to continue using
+Synchronous {+driver-short+}, consider the information in this section.
+
+Synchronous {+driver-short+} is preferable if the following criteria applies to your
+application or use case:
+
+- Your application is simple in execution, or you prefer to avoid using asynchronous calls
+ in your code
+
+- Your application relies on serial workloads or workloads with very fast
+ response times
+
+- You prefer the simplicity of synchronous logic when debugging your application
+
+Consider migrating to the {+driver-async+} driver if the following criteria applies
+to your application or use case:
+
+- Your application implements large, highly concurrent workloads (on the order of
+ thousands of concurrent operations)
+
+- Your application relies on workloads that spend a long time waiting for responses or
+ writing data
+
+- Your application relies on other asynchronous libraries or frameworks, such as FastAPI
+
Migrate From Motor
------------------
+.. warning:: Motor Deprecation
+
+ Motor will be deprecated one year after the production release of the {+driver-async+}
+ driver. We strongly recommend that Motor users migrate to the {+driver-async+} driver while
+ Motor is still supported.
+
The {+driver-async+} driver functions similarly to the Motor library, but allows
for improved latency and throughput due to directly using Python Asyncio instead
of delegating work to a thread pool. In most cases, you can directly migrate
@@ -50,12 +84,17 @@ read and write operations in Motor compared to {+driver-async+}:
from pymongo import AsyncMongoClient
To see a list of the asynchronous methods available in the {+driver-async+}
-driver, see the :ref:`pymongo-async-methods` section in the {+driver-short+} to
-{+driver-async+} guide.
+driver, see the :ref:`pymongo-async-methods` section. To learn about the versions of Motor
+that correspond to {+driver-short+}, see the :ref:`pymongo-motor-compatibility` section of
+the Compatibility guide.
The following section shows the method signature changes that you must implement
in your application when migrating from Motor to the {+driver-async+} driver.
+.. warning::
+
+ The {+driver-async+} driver does not support Tornado.
+
Method Signature Changes
~~~~~~~~~~~~~~~~~~~~~~~~
@@ -70,6 +109,21 @@ The following Motor method signatures behave differently in the {+driver-async+}
``AsyncMongoClient`` is not thread safe and should only be used by a single
event loop.
+.. warning::
+
+ Motor users may experience a degradation of performance when switching to the
+ {+driver-async+} driver. This is due to the {+driver-async+} driver using native
+ ``asyncio`` tasks instead of thread-based executors. Thread-based executors
+ have similar performance characteristics to the synchronous driver, but slower.
+ This means they perform better for workloads that do not fit the preceding criteria
+ for the {+driver-async+} driver.
+
+ If you are experiencing performance slowdown, identify whether the {+driver-async+} driver
+ is necessary for your usecase. If you determine your use case is better served by
+ synchronous {+driver-short+}, consider using the synchronous driver
+ with ``asyncio.loop.run_in_executor()`` for asynchronous compatibility. To learn more, see
+ the `Event Loop API documentation `__.
+
.. _pymongo-to-async-guide:
Migrate from {+driver-short+}
@@ -82,294 +136,39 @@ in the following ways:
- Replace all uses of ``MongoClient`` with ``AsyncMongoClient``.
- Add the ``await`` keyword to all asynchronous method calls.
-- If you call an asynchronous method inside of a function, mark the function as ``async``.
-
-The following sections describe how to implement the asynchronous API.
-
-.. _pymongo-async-methods:
-
-Asynchronous Methods
-~~~~~~~~~~~~~~~~~~~~
-
-The following tables list the asynchronous methods that are available in the
-{+driver-async+} driver. To call these methods, you must ``await`` them and call them
-inside an ``async`` function.
-
-Client Methods
-``````````````
-
-.. list-table::
- :header-rows: 1
- :widths: 20 80
-
- * - Method
- - Example
-
- * - ``AsyncMongoClient()``
- - .. code-block:: python
-
- from pymongo import AsyncMongoClient
-
- async with AsyncMongoClient(...)
-
- * - ``watch()``
- - .. code-block:: python
-
- async with await client.watch(...) as stream:
- ...
-
- * - ``server_info()``
- - .. code-block:: python
-
- await client.server_info(...)
-
- * - ``list_databases()``
- - .. code-block:: python
-
- await client.list_databases()
-
- * - ``list_database_names()``
- - .. code-block:: python
-
- await client.list_database_names()
-
- * - ``drop_database()``
- - .. code-block:: python
-
- await client.drop_database(...)
-
-Database Methods
-````````````````
-
-.. list-table::
- :header-rows: 1
- :widths: 20 80
-
- * - Method
- - Example
-
- * - ``watch()``
- - .. code-block:: python
-
- async with await db.watch(...) as stream:
- ...
-
- * - ``create_collection()``
- - .. code-block:: python
-
- await db.create_collection(...)
-
- * - ``aggregate()``
- - .. code-block:: python
-
- async with await client.admin.aggregate(...) as cursor:
- ...
-
- * - ``command()``
- - .. code-block:: python
-
- await db.command(...)
-
- * - ``cursor_command()``
- - .. code-block:: python
-
- await db.cursor_command(...)
-
- * - ``list_collections()``
- - .. code-block:: python
-
- await db.list_collections()
-
- * - ``list_collection_names()``
- - .. code-block:: python
+- If you call an asynchronous method inside a function, mark the function as ``async``.
- await db.list_collection_names()
+Keep the following points in mind when migrating from synchronous {+driver-short+}
+to the {+driver-async+} driver:
- * - ``drop_collection()``
- - .. code-block:: python
+- To convert an ``AsyncCursor`` to a list, you must use the asynchronous ``cursor.to_list()``
+ method.
+- The ``AsyncCollection.find()`` method in the {+driver-async+} driver is synchronous, but
+ returns an ``AsyncCursor``. To iterate through the cursor, you must use an ``async for``
+ loop.
+- The ``AsyncMongoClient`` object does not support the ``connect`` keyword argument.
+- You cannot share ``AsyncMongoClient`` objects across threads or event loops.
+- To access a property or method of a result returned by an asynchronous call, you must
+ properly wrap the call in parentheses, as shown in the following example:
- await db.drop_collection(...)
+ .. code-block:: python
+
+ id = (await posts.insert_one(doc)).inserted_id
- * - ``validate_collection()``
- - .. code-block:: python
-
- await db.validate_collection(...)
-
- * - ``dereference()``
- - .. code-block:: python
-
- await db.dereference(...)
-
-Collection Methods
-``````````````````
-
-.. list-table::
- :header-rows: 1
- :widths: 20 80
-
- * - Method
- - Example
-
- * - ``watch()``
- - .. code-block:: python
-
- async with await collection.watch(...) as stream:
- ...
-
- * - ``insert_one()``
- - .. code-block:: python
-
- await collection.insert_one(...)
-
- * - ``insert_many()``
- - .. code-block:: python
-
- await collection.insert_many(...)
-
- * - ``replace_one()``
- - .. code-block:: python
-
- await collection.replace_one(...)
-
- * - ``update_one()``
- - .. code-block:: python
-
- await collection.update_one(...)
-
- * - ``update_many()``
- - .. code-block:: python
-
- await collection.update_many(...)
-
- * - ``drop()``
- - .. code-block:: python
-
- await collection.drop()
-
- * - ``delete_one()``
- - .. code-block:: python
-
- await collection.delete_one(...)
-
- * - ``delete_many()``
- - .. code-block:: python
-
- await collection.delete_many(...)
-
- * - ``find_one()``
- - .. code-block:: python
-
- await collection.find_one(...)
-
- * - ``estimated_document_count()``
- - .. code-block:: python
-
- await collection.estimated_document_count()
-
- * - ``count_documents()``
- - .. code-block:: python
-
- await collection.count_documents(...)
-
- * - ``create_index()``
- - .. code-block:: python
-
- await collection.create_index(...)
-
- * - ``create_indexes()``
- - .. code-block:: python
-
- await collection.create_indexes(...)
-
- * - ``drop_index()``
- - .. code-block:: python
-
- await collection.drop_index(...)
-
- * - ``drop_indexes()``
- - .. code-block:: python
-
- await collection.drop_indexes()
-
- * - ``list_indexes()``
- - .. code-block:: python
-
- await collection.list_indexes()
-
- * - ``index_information()``
- - .. code-block:: python
-
- await collection.index_information()
-
- * - ``list_search_indexes()``
- - .. code-block:: python
-
- await collection.list_search_indexes()
-
- * - ``create_search_index()``
- - .. code-block:: python
-
- await collection.create_search_index(...)
-
- * - ``create_search_indexes()``
- - .. code-block:: python
-
- await collection.create_search_indexes(...)
-
- * - ``drop_search_index()``
- - .. code-block:: python
-
- await collection.drop_search_index(...)
-
- * - ``update_search_index()``
- - .. code-block:: python
-
- await collection.update_search_index(...)
-
- * - ``options()``
- - .. code-block:: python
-
- await collection.options()
-
- * - ``aggregate()``
- - .. code-block:: python
-
- async for doc in await collection.aggregate(...):
- ...
-
- * - ``aggregate_raw_batches()``
- - .. code-block:: python
-
- async for batch in await collection.aggregate_raw_batches(...):
- ...
-
- * - ``rename()``
- - .. code-block:: python
-
- await collection.rename(...)
-
- * - ``distinct()``
- - .. code-block:: python
-
- await collection.distinct(...)
-
- * - ``find_one_and_delete()``
- - .. code-block:: python
-
- await collection.find_one_and_delete(...)
+.. _pymongo-async-methods:
- * - ``find_one_and_replace()``
- - .. code-block:: python
+Asynchronous Methods
+--------------------
- await collection.find_one_and_replace(...)
+For a complete list of asynchronous methods available in the {+driver-async+} driver,
+see the `API documentation <{+api-root+}pymongo/asynchronous/index.html>`__.
- * - ``find_one_and_update()``
- - .. code-block:: python
+.. note::
- await collection.find_one_and_update(...)
+ Any methods not listed in the preceding API documentation are synchronous.
Additional Information
----------------------
To learn more about asynchronous Python, see the `Python Asyncio documentation
-`__.
\ No newline at end of file
+`__.