Bird
Raised Fist0
FastAPIframework~5 mins

MongoDB integration with Motor in FastAPI

Choose your learning style10 modes available

Start learning this pattern below

Jump into concepts and practice - no test required

or
Recommended
Test this pattern10 questions across easy, medium, and hard to know if this pattern is strong
Introduction

We use Motor to connect FastAPI with MongoDB because Motor lets us talk to the database without stopping our app. It works smoothly with FastAPI's async style.

When you want to save user data from a web form into MongoDB.
When you need to fetch and show data from MongoDB in a FastAPI app.
When you want your FastAPI app to handle many database requests at the same time without slowing down.
When you want to update or delete records in MongoDB from your FastAPI backend.
Syntax
FastAPI
from motor.motor_asyncio import AsyncIOMotorClient

client = AsyncIOMotorClient('mongodb://localhost:27017')
db = client['database_name']
collection = db['collection_name']

# Example async function to insert a document
async def insert_document(doc):
    result = await collection.insert_one(doc)
    return result.inserted_id

Use AsyncIOMotorClient to create a connection that works with async code.

Always use await when calling Motor methods to avoid blocking.

Examples
Connect to MongoDB on your local machine and select the 'testdb' database and 'users' collection.
FastAPI
client = AsyncIOMotorClient('mongodb://localhost:27017')
db = client['testdb']
collection = db['users']
Insert a new user document asynchronously and get its unique ID.
FastAPI
async def add_user(user_data):
    result = await collection.insert_one(user_data)
    return result.inserted_id
Find one user document by name asynchronously.
FastAPI
async def find_user(name):
    user = await collection.find_one({'name': name})
    return user
Sample Program

This FastAPI app connects to MongoDB using Motor. It has two routes: one to add an item and one to get an item by name.

FastAPI
from fastapi import FastAPI
from motor.motor_asyncio import AsyncIOMotorClient

app = FastAPI()

client = AsyncIOMotorClient('mongodb://localhost:27017')
db = client['sampledb']
collection = db['items']

@app.post('/items/')
async def create_item(item: dict):
    inserted_id = await collection.insert_one(item)
    return {'inserted_id': str(inserted_id.inserted_id)}

@app.get('/items/{name}')
async def read_item(name: str):
    item = await collection.find_one({'name': name})
    if item:
        item['_id'] = str(item['_id'])
        return item
    return {'error': 'Item not found'}
OutputSuccess
Important Notes

Motor is an async driver, so always use async functions and await Motor calls.

Convert MongoDB ObjectId to string before returning JSON to avoid errors.

Make sure MongoDB server is running before connecting.

Summary

Motor lets FastAPI talk to MongoDB without waiting or blocking.

Use async functions and await Motor calls to keep your app fast.

Remember to convert ObjectId to string when sending data back to users.

Practice

(1/5)
1. What is the main benefit of using Motor with FastAPI for MongoDB operations?
easy
A. It automatically converts ObjectId to string.
B. It provides a graphical interface for MongoDB.
C. It allows asynchronous, non-blocking database calls.
D. It replaces the need for FastAPI routing.

Solution

  1. Step 1: Understand Motor's role in FastAPI

    Motor is an async driver for MongoDB, enabling non-blocking calls in FastAPI apps.
  2. Step 2: Identify the main benefit

    Non-blocking calls keep the app responsive and fast by not waiting for DB operations.
  3. Final Answer:

    It allows asynchronous, non-blocking database calls. -> Option C
  4. Quick Check:

    Motor = async, non-blocking calls [OK]
Hint: Motor means async MongoDB calls in FastAPI [OK]
Common Mistakes:
  • Thinking Motor provides UI tools
  • Assuming Motor auto-converts ObjectId
  • Confusing Motor with FastAPI routing
2. Which of the following is the correct way to define a Motor client in FastAPI?
easy
A. client = motor.motor_asyncio.AsyncIOMotorClient('mongodb://localhost:27017')
B. client = MotorClient('mongodb://localhost:27017')
C. client = AsyncMongoClient('localhost:27017')
D. client = motor.MongoClient('mongodb://localhost:27017')

Solution

  1. Step 1: Recall Motor client syntax

    The Motor async client is created using motor.motor_asyncio.AsyncIOMotorClient with the MongoDB URI.
  2. Step 2: Check each option

    Only client = motor.motor_asyncio.AsyncIOMotorClient('mongodb://localhost:27017') uses the correct class and URI format for Motor.
  3. Final Answer:

    client = motor.motor_asyncio.AsyncIOMotorClient('mongodb://localhost:27017') -> Option A
  4. Quick Check:

    Motor client = AsyncIOMotorClient [OK]
Hint: Use AsyncIOMotorClient from motor.motor_asyncio [OK]
Common Mistakes:
  • Using MotorClient instead of AsyncIOMotorClient
  • Omitting 'motor.motor_asyncio' prefix
  • Using synchronous MongoClient
3. Given this FastAPI async function using Motor, what will be the output?
async def get_user(db, user_id):
    user = await db.users.find_one({"_id": user_id})
    return str(user["_id"])
medium
A. Returns None if user_id is not found.
B. Returns the string representation of the user's ObjectId.
C. Raises a TypeError because ObjectId can't be converted to string.
D. Returns the user document as a dictionary.

Solution

  1. Step 1: Analyze the async function

    The function awaits a find_one query by _id and then converts the _id field to string.
  2. Step 2: Understand the output

    It returns the string form of the ObjectId, not the whole document or None.
  3. Final Answer:

    Returns the string representation of the user's ObjectId. -> Option B
  4. Quick Check:

    str(ObjectId) = string id [OK]
Hint: str() converts ObjectId to string safely [OK]
Common Mistakes:
  • Expecting full user dict as output
  • Thinking ObjectId can't be stringified
  • Assuming None is returned if not found
4. Identify the error in this Motor usage inside FastAPI:
async def fetch_items(db):
    items = db.items.find()
    return await items.to_list(length=100)
medium
A. Missing await before db.items.find() call.
B. to_list() should not be awaited.
C. find() returns a cursor and must be awaited before to_list().
D. No error; code is correct.

Solution

  1. Step 1: Understand Motor's find() behavior

    Motor's find() returns an async cursor immediately; no await needed here.
  2. Step 2: Check to_list() usage

    to_list() is a coroutine and must be awaited to get the list of documents.
  3. Final Answer:

    No error; code is correct. -> Option D
  4. Quick Check:

    find() no await, to_list() await [OK]
Hint: Await to_list(), not find() [OK]
Common Mistakes:
  • Awaiting find() call incorrectly
  • Not awaiting to_list() causing runtime error
  • Confusing synchronous and async cursor methods
5. You want to return a list of users from MongoDB in FastAPI, but each user's _id must be a string, not ObjectId. Which code snippet correctly does this?
hard
A. users = await db.users.find().to_list(100) return [{**u, '_id': str(u['_id'])} for u in users]
B. users = await db.users.find().to_list(100) return [u for u in users if str(u['_id'])]
C. users = await db.users.find().to_list(100) return [str(u) for u in users]
D. users = await db.users.find().to_list(100) return [u['_id'] for u in users]

Solution

  1. Step 1: Fetch users as list of dicts

    await db.users.find().to_list(100) returns list of user dicts with ObjectId _id fields.
  2. Step 2: Convert each user's _id to string

    Use list comprehension to copy each dict and replace _id with str(u['_id']).
  3. Final Answer:

    users = await db.users.find().to_list(100) return [{**u, '_id': str(u['_id'])} for u in users] -> Option A
  4. Quick Check:

    Convert ObjectId to string per user [OK]
Hint: Use dict unpacking and str() on _id in list comprehension [OK]
Common Mistakes:
  • Returning ObjectId directly without conversion
  • Trying to convert whole user dict to string
  • Filtering users instead of converting _id