异步之舞:FastAPI与MongoDB的深度协奏
title: 异步之舞:FastAPI与MongoDB的深度协奏
date: 2025/05/18 19:09:08
updated: 2025/05/18 19:09:08
author: cmdragon
excerpt:
MongoDB与FastAPI的基础集成方法。首先,环境要求包括Python 3.8+、MongoDB 4.4+、FastAPI 0.95+和Motor 3.1+,并提供了依赖安装命令。其次,通过Motor驱动配置异步数据库连接,使用Pydantic进行数据验证,并实现异步CRUD操作。此外,还展示了聚合管道实践和索引优化策略,如创建单字段索引、复合索引和文本索引。最后,提供了常见报错的解决方案,如ServerSelectionTimeoutError、ValidationError和查询性能低下的处理方法。
categories:
- 后端开发
- FastAPI
tags:
- MongoDB
- FastAPI
- 异步编程
- 数据库集成
- CRUD操作
- 聚合管道
- 索引优化

扫描二维码
关注或者微信搜一搜:编程智域 前端至全栈交流与成长
探索数千个预构建的 AI 应用,开启你的下一个伟大创意:https://tools.cmdragon.cn/
第一章:MongoDB 与 FastAPI 基础集成
1.1 环境准备与依赖安装
运行环境要求
- Python 3.8+
- MongoDB 4.4+
- FastAPI 0.95+
- Motor 3.1+
安装所需依赖:
pip install fastapi==0.95.0
pip install motor==3.1.2
pip install pydantic==1.10.7
pip install python-multipart==0.0.6
pip install uvicorn==0.21.1
1.2 异步数据库连接
Motor驱动配置
from fastapi import FastAPI
from motor.motor_asyncio import AsyncIOMotorClient
from pydantic import BaseModel, Field
import os
app = FastAPI()
# MongoDB配置模型
class MongoDBConfig:
MONGO_URI = os.getenv("MONGO_URI", "mongodb://localhost:27017")
DB_NAME = "fastapi_demo"
COLLECTION = "users"
# 异步数据库客户端
@app.on_event("startup")
async def startup_db_client():
app.mongodb_client = AsyncIOMotorClient(MongoDBConfig.MONGO_URI)
app.mongodb = app.mongodb_client[MongoDBConfig.DB_NAME]
@app.on_event("shutdown")
async def shutdown_db_client():
app.mongodb_client.close()
1.3 数据模型与CRUD操作
Pydantic数据验证
from bson import ObjectId
from typing import Optional
class PyObjectId(ObjectId):
@classmethod
def __get_validators__(cls):
yield cls.validate
@classmethod
def validate(cls, v):
if not ObjectId.is_valid(v):
raise ValueError("Invalid ObjectId")
return ObjectId(v)
class UserCreate(BaseModel):
name: str = Field(..., min_length=3)
age: int = Field(..., gt=0)
tags: list[str] = []
class UserResponse(UserCreate):
id: PyObjectId = Field(default_factory=PyObjectId, alias="_id")
class Config:
json_encoders = {ObjectId: str}
异步CRUD实现
插入文档
@app.post("/users/")
async def create_user(user: User):
result = await db.users.insert_one(user.dict())
return {"id": str(result.inserted_id)}
查询文档
@app.get("/users/{user_id}")
async def read_user(user_id: str):
if not ObjectId.is_valid(user_id):
raise HTTPException(400, "Invalid ID format")
user = await db.users.find_one({"_id": ObjectId(user_id)})
if not user:
raise HTTPException(404, "User not found")
# 转换 MongoDB 的 ObjectId 为字符串
user["id"] = str(user.pop("_id"))
return user
更新文档
@app.patch("/users/{user_id}")
async def update_user(user_id: str, update_data: dict):
# 过滤无效字段
valid_fields = User.__annotations__.keys()
filtered_data = {k: v for k, v in update_data.items() if k in valid_fields}
result = await db.users.update_one(
{"_id": ObjectId(user_id)},
{"$set": filtered_data}
)
return {"modified_count": result.modified_count}
1.4 聚合管道实践
用户分析接口
from fastapi import APIRouter
router = APIRouter()
@router.get("/users/stats/age-distribution")
async def get_age_distribution():
pipeline = [
{"$group": {
"_id": "$age",
"count": {"$sum": 1}
}},
{"$sort": {"_id": 1}}
]
results = []
async for doc in app.mongodb.users.aggregate(pipeline):
results.append({
"age": doc["_id"],
"count": doc["count"]
})
return results
1.5 索引优化策略
索引创建示例
async def create_indexes():
# 单字段索引
await app.mongodb.users.create_index("name", unique=True)
# 复合索引
await app.mongodb.users.create_index([("age", 1), ("tags", 1)])
# 文本索引
await app.mongodb.users.create_index([("name", "text")])
课后Quiz
为什么在FastAPI中推荐使用Motor驱动而不是同步的PyMongo?
答案:FastAPI基于异步架构,Motor作为异步驱动可以避免阻塞事件循环,提升系统吞吐量。PyMongo的同步操作会阻塞整个事件循环,导致性能下降。配置 Motor 驱动时,为什么要传入
io_loop=app.state.loop参数?- A. 为了提升查询速度
- B. 确保使用相同的事件循环
- C. 强制使用同步模式
- 答案:B,保证异步驱动使用与 FastAPI 相同的事件循环
处理 MongoDB 的日期字段时,Pydantic 模型为什么推荐使用
datetime.utcnow()?- A. 减少存储空间
- B. 避免时区混乱
- C. 提高序列化速度
- 答案:B,统一使用 UTC 时间可避免时区转换问题
当收到"422 Unprocessable Entity"错误时,应该如何快速定位问题?
答案:检查请求数据是否符合Pydantic模型定义,使用Swagger文档验证请求格式。错误响应体包含详细的字段验证信息。如何验证用户年龄字段必须是正整数?
age: int = Field(..., gt=0)
该定义表示age必须大于0(gt=greater than)
常见报错解决方案
错误1:ServerSelectionTimeoutError
- 现象:连接MongoDB超时
- 原因:MongoDB服务未启动或配置错误
- 解决:
- 检查MongoDB服务状态:
sudo systemctl status mongod - 验证连接字符串格式:
mongodb://username:password@host:port
- 检查MongoDB服务状态:
错误2:ValidationError
- 现象:返回422状态码
- 原因:请求数据不符合Pydantic模型
- 解决:
- 查看错误响应中的detail字段
- 使用try-except捕获ValidationError:
from fastapi.exceptions import RequestValidationError @app.exception_handler(RequestValidationError)
async def validation_exception_handler(request, exc):
return JSONResponse(status_code=400, content={"detail": exc.errors()})
错误3:查询性能低下
- 现象:API响应缓慢
- 解决:
- 使用
explain()分析查询计划 - 创建合适索引
- 优化聚合管道阶段顺序
- 使用
余下文章内容请点击跳转至 个人博客页面 或者 扫码关注或者微信搜一搜:编程智域 前端至全栈交流与成长,阅读完整的文章:异步之舞:FastAPI与MongoDB的深度协奏 | cmdragon's Blog
往期文章归档:
- 数据库迁移的艺术:FastAPI生产环境中的灰度发布与回滚策略 | cmdragon's Blog
- 数据库迁移的艺术:团队协作中的冲突预防与解决之道 | cmdragon's Blog
- 驾驭FastAPI多数据库:从读写分离到跨库事务的艺术 | cmdragon's Blog
- 数据库事务隔离与Alembic数据恢复的实战艺术 | cmdragon's Blog
- FastAPI与Alembic:数据库迁移的隐秘艺术 | cmdragon's Blog
- 飞行中的引擎更换:生产环境数据库迁移的艺术与科学 | cmdragon's Blog
- Alembic迁移脚本冲突的智能检测与优雅合并之道 | cmdragon's Blog
- 多数据库迁移的艺术:Alembic在复杂环境中的精妙应用 | cmdragon's Blog
- 数据库事务回滚:FastAPI中的存档与读档大法 | cmdragon's Blog
- Alembic迁移脚本:让数据库变身时间旅行者 | cmdragon's Blog
- 数据库连接池:从银行柜台到代码世界的奇妙旅程 | cmdragon's Blog
- 点赞背后的技术大冒险:分布式事务与SAGA模式 | cmdragon's Blog
- N+1查询:数据库性能的隐形杀手与终极拯救指南 | cmdragon's Blog
- FastAPI与Tortoise-ORM开发的神奇之旅 | cmdragon's Blog
- DDD分层设计与异步职责划分:让你的代码不再“异步”混乱 | cmdragon's Blog
- 异步数据库事务锁:电商库存扣减的防超卖秘籍 | cmdragon's Blog
- FastAPI中的复杂查询与原子更新指南 | cmdragon's Blog
- 深入解析Tortoise-ORM关系型字段与异步查询 | cmdragon's Blog
- FastAPI与Tortoise-ORM模型配置及aerich迁移工具 | cmdragon's Blog
- 异步IO与Tortoise-ORM的数据库 | cmdragon's Blog
- FastAPI数据库连接池配置与监控 | cmdragon's Blog
- 分布式事务在点赞功能中的实现 | cmdragon's Blog
- Tortoise-ORM级联查询与预加载性能优化 | cmdragon's Blog
- 使用Tortoise-ORM和FastAPI构建评论系统 | cmdragon's Blog
- 分层架构在博客评论功能中的应用与实现 | cmdragon's Blog
- 深入解析事务基础与原子操作原理 | cmdragon's Blog
- 掌握Tortoise-ORM高级异步查询技巧 | cmdragon's Blog
- FastAPI与Tortoise-ORM实现关系型数据库关联 | cmdragon's Blog
- Tortoise-ORM与FastAPI集成:异步模型定义与实践 | cmdragon's Blog
- 异步编程与Tortoise-ORM框架 | cmdragon's Blog
- FastAPI数据库集成与事务管理 | cmdragon's Blog
- FastAPI与SQLAlchemy数据库集成 | cmdragon's Blog
- FastAPI与SQLAlchemy数据库集成与CRUD操作 | cmdragon's Blog
- FastAPI与SQLAlchemy同步数据库集成 | cmdragon's Blog
- XML Sitemap
异步之舞:FastAPI与MongoDB的深度协奏的更多相关文章
- [原]分享一下我和MongoDB与Redis那些事
缘起:来自于我在近期一个项目上遇到的问题,在Segmentfault上发表了提问 知识背景: 对不是很熟悉MongoDB和Redis的同学做一下介绍. 1.MongoDB数组查询:MongoDB自带L ...
- NodeJs连接操作MongoDB数据库
NodeJs连接操作MongoDB数据库 一,介绍 MongoDB是一种文档导向数据库管理系统,由C++撰写而成.介绍如何使用 Node.js 来连接 MongoDB,并对数据库进行操作. Mongo ...
- mongoDB与mongoose
mongodb是一个基于分布式文件存储的文档型数据库 MongoDB 是一个介于关系数据库和非关系数据库之间的产品 MongoDB 最大的特点是他支持的查询语言非常强大,而且还支持对数据建立索引 官方 ...
- Mongodb简单介绍安装
具体详细内容,请查阅 Mongodb官方文档 一.简单介绍 MongoDB 是由C++语言编写的,是一个基于分布式文件存储的开源数据库系统. 在高负载的情况下,添加更多的节点,可以保证服务器性能. M ...
- mongodb学习(3)--- NodeJs使用mongoose操作mongodb
转载: https://cnodejs.org/topic/50c145ed637ffa4155c7eaee 首先对于以下错误说明(有写 db.close): Error: db object alr ...
- MongoDB学习day07--mongoose入门,数据库增删改查,默认参数,模块化
一.mongoose介绍 Mongoose 是在 node.js 异步环境下对 mongodb 进行便捷操作的对象模型工具. Mongoose 是 NodeJS 的驱动, 不能作为其他语言的驱动. M ...
- MongoDB(一):NoSQL简介、MongoDB简介
1. NoSQL简介 1.1 什么是NoSQL NoSQL(NoSQL= Not Only SQL),意即“不仅仅是SQL",是一项全新的数据库理念,泛指非关系型的数据库. 1.2 为什么需 ...
- 【玩转SpringBoot】异步任务执行与其线程池配置
同步代码写起来简单,但就是怕遇到耗时操作,会影响效率和吞吐量. 此时异步代码才是王者,但涉及多线程和线程池,以及异步结果的获取,写起来颇为麻烦. 不过在遇到SpringBoot异步任务时,这个问题就不 ...
- 【Mongodb】mongoDB与mongoose---Scheme和Collections对应问题
mongodb是一个基于分布式文件存储的文档型数据库 MongoDB 是一个介于关系数据库和非关系数据库之间的产品 MongoDB 最大的特点是他支持的查询语言非常强大,而且还支持对数据建立索引 官方 ...
- python浅学【网络服务中间件】之MongoDB
一.关于MongoDB: MongoDB 是由C++语言编写的,是一个基于分布式文件存储的开源数据库系统. 在高负载的情况下,添加更多的节点,可以保证服务器性能. MongoDB 旨在为WEB应用提供 ...
随机推荐
- JUC并发—12.ThreadLocal源码分析
大纲 1.ThreadLocal的特点介绍 2.ThreadLocal的使用案例 3.ThreadLocal的内部结构 4.ThreadLocal的核心方法源码 5.ThreadLocalMap的核心 ...
- FishSpeech应用篇——专属朗读人
背景 FishSpeech部署教程参见:使用FishSpeech进行语音合成推理 - 天命小猪 - 博客园 部署好之后,就能够基于推理来定制自己专属朗读人.编程能力强的小伙伴可以结合AI定制一个自己的 ...
- Typecho头像被墙的解决方法
首先下载最新开发版本的TYPECHO,然后,在config.inc.php自定义如下: /** 自定义gravatar url前缀 */ define('__TYPECHO_GRAVATAR_PREF ...
- Typecho自定义右键菜单美化和禁用F12
右键美化 使用右键美化,请禁用 HoerMouse 鼠标美化插件,否则貌似没效果 Joe主题在后台-外观设置-设置外观-全局设置-自定义<body></body>标签内填入如下 ...
- Typecho 数据备份及程序升级详细步骤教程
数据库备份看自己,习惯性更新前都备份,出错直接滚回去 数据库备份 直接在宝塔数据库那个模块备份即可,备份完建议下载本地或者保存到OSS 备份网站文件 理论上只需要备份/usr/目录即可,因为这个目录包 ...
- nginx 配置 vue History模式
解决 需要加一行 try_files $uri $uri/ /index.html;,其中 /index.html 是你自己的目录中的入口文件 server { listen [::]:80 defa ...
- ModuleNotFoundError: No module named '_bz2'
前言 运行 python 报错:ModuleNotFoundError: No module named '_bz2' when building python 解决 安装在 Ubuntu/Debia ...
- Golang入门:协程(goroutine)
goroutine goroutine 是 Go 的并发模型的核心概念.为了理解 goroutine,我们来定义几个术语.第一个是进程.进程是程序的实例,由计算机的操作系统运行.操作系统将一些资源(如 ...
- bug|项目经验|记录某次页面div使用v-html标签渲染图片等内容的过程
前言 记录某次页面div使用v-html标签渲染图片等内容的过程 一.结论: get请求但被设置Sec-Fetch-*请求头的图片无法展示. 二.原因: 1.本项目中的img标签发起get请求,目标链 ...
- 保姆级教程——手把手教会你如何在Linux上安装Redis
一.Linux系统安装Redis(7.4.0) 注意: 全程是在root底下操作,当然也可以采用sudo 1.1 安装Redis依赖 Redis是基于C语言编写的,因此首先需要安装Redis所需要的g ...