PyMongo(Motor)报DuplicateKeyError且try-except不生效如何处理
Motor异步写入MongoDB时DuplicateKeyError无法捕获的解决方法
问题根因
现有代码的异常捕获不生效,核心是两个写法错误:
- Motor作为异步MongoDB驱动,所有数据读写方法返回协程对象,必须加
await关键字才会实际执行。当前add_user是同步函数,调用insert_one时仅发起了操作请求,没有等待操作执行完成就退出了try块,等实际写入触发重复键错误时,已经不在异常捕获的作用域内。 - 未正确等待异步协程执行,导致异常抛出时没有对应的捕获逻辑承接。
修复方案
方案1:修正异步逻辑+显式捕获重复键异常
首先导入重复键对应的异常类,将数据库操作函数改为异步函数,调用时增加await等待执行完成,再针对性捕获异常即可。
完整修正代码:
import motor.motor_asyncio from datetime import datetime from pymongo.errors import DuplicateKeyError from aiogram import Bot, types from aiogram.dispatcher import Dispatcher from aiogram.utils import executor TOKEN = '' cluster = motor.motor_asyncio.AsyncIOMotorClient('') collection = cluster.Dimalexus.BOT bot = Bot(token=TOKEN) dp = Dispatcher(bot) async def add_user(user_id, user_name, name): date = datetime.now().date() await collection.insert_one({ '_id' : user_id, 'name' : name, "username" : user_name, "date" : str(date) }) @dp.message_handler(commands=['start']) async def welcome_send_info(message: types.Message): await message.reply('привет') name = message.from_user.full_name user_name = message.from_user.username user_id = message.from_user.id try: await add_user(user_id, user_name, name) except DuplicateKeyError: # 用户已存在,跳过重复插入逻辑 pass except Exception as e: print(f"用户数据写入异常: {e}") if __name__ == "__main__": executor.start_polling(dp, skip_updates=True)
方案2:使用upsert原子操作规避重复键错误(推荐)
不需要依赖异常捕获处理重复用户场景,直接使用update_one搭配upsert=True实现原子写入:如果用户_id不存在就插入新记录,如果已存在就更新用户最新的昵称、用户名信息,从根源上避免重复键报错,逻辑更健壮、性能更好。
对应修改add_user函数即可:
async def add_user(user_id, user_name, name): date = datetime.now().date() await collection.update_one( filter={"_id": user_id}, update={ "$setOnInsert": {"date": str(date)}, "$set": {"name": name, "username": user_name} }, upsert=True )
其中$setOnInsert修饰的字段只会在首次插入新用户时写入,不会覆盖用户原有的注册日期;$set修饰的字段每次用户触发/start时都会同步更新,能自动适配用户修改昵称、用户名的场景。
内容的提问来源于stack exchange,提问作者bybacapitan
相关产品推荐
相关产品推荐

