motor是唯一真正异步的mongodb python驱动,pymongo无法通过async/await实现真异步;asynciomotorclient需await初始化,连接字符串含mongodb+srv://时须手动设tls=true;insert_one/many返回封装对象,取id需用.inserted_id/.inserted_ids属性;find()返回asynciomotorcursor,须用async for或.to_list();update/delete操作不自动抛异常,需检查结果对象字段。

Motor 是唯一能真正异步操作 MongoDB 的 Python 驱动,pymongo 再怎么套 async/await 也会卡死事件循环 —— 它底层是同步阻塞 I/O,不是“加个 await 就变异步”。
AsyncIOMotorClient 初始化必须 await 才生效
写 client = AsyncIOMotorClient("mongodb://...") 只是创建了一个连接工厂,不触发任何网络行为。直接调 collection.find_one() 会静默失败或抛 RuntimeError: There is no current event loop in thread。
- 必须在协程里显式
await client.admin.command("ping")来触发连接建立和权限校验 - 生产环境更推荐用
async with管理生命周期,尤其短任务或测试场景 - 别漏设关键参数:
maxPoolSize=300(默认 100 容易耗尽)、retryWrites=True(副本集必需) - 连接字符串含
mongodb+srv://时,务必手动加tls=True,否则可能连上但认证失败
insert_one / insert_many 返回值不是 dict,不能用下标取字段
很多人写 result["inserted_id"] 直接报 TypeError: 'InsertOneResult' object is not subscriptable —— Motor 返回的是封装对象,不是字典。
-
insert_one返回InsertOneResult,取 ID 用.inserted_id属性 -
insert_many返回InsertManyResult,ID 列表在.inserted_ids(list 类型),不是.ids - 如果插入时指定了
_id(比如字符串"user_123"),.inserted_id就是那个值,不是ObjectId
find() 返回游标,不能 for 循环或索引
collection.find({}) 返回的是 AsyncIOMotorCursor,它不支持同步迭代、不能 list(cursor)、也不能 cursor[0] —— 这些都会立刻报错。
- 逐条处理用
async for doc in cursor: - 小批量全量加载用
await cursor.to_list(length=100);length=None表示全取(慎用,OOM 风险高) - 只取第一条等价于
find_one,但若已调了find(),可用await cursor.next() - 聚合操作
aggregate()同样返回游标,不能await collection.aggregate(pipeline),会 TypeError
update/delete 不自动抛异常,失败需主动检查
Motor 的写操作默认“发出去就返回”,哪怕 MongoDB 回复写入失败(如唯一键冲突、类型校验失败),也不会 raise 异常 —— 这和 pymongo 行为不同,极易漏掉错误。
-
update_one返回UpdateResult,查.matched_count和.modified_count判断是否命中、是否真改了 -
delete_one返回DeleteResult,看.deleted_count是否为 1 - 没匹配到文档时,
modified_count == 0是正常情况,不是错误;但matched_count == 0可能意味着查询条件写错了 - 所有写操作都建议配合
upsert=True或唯一索引 + 异常捕获来兜底
最容易被忽略的点:Motor 客户端可全局单例复用,但必须确保初始化后至少有一次 await 触发连接;另外,to_list(length=None) 在大数据集上等于把整个集合拉进内存,别在没评估数据量时乱用。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











