pymongo偶发无明确诱因的bson.errors.InvalidDocument报错问题
故障根因分析
db.systems.find()方法返回的是pymongo.cursor.Cursor游标对象,不会直接拉取所有匹配结果。你直接通过[0]下标取数时,pymongo会动态向服务端发起数据拉取请求,遇到网络波动、服务端游标过期、连接重置等情况时,就会触发序列化异常,表现为偶发报错。- 排查上游调用逻辑,不排除偶发传入的
_id参数本身是游标对象的可能,这也会直接触发查询条件序列化失败的报错。
修复方案
最优方案:改用find_one查询单条数据
你只需要匹配单条_id对应的记录,直接用find_one方法即可,该方法会直接返回文档字典,不需要处理游标逻辑:
def getEnergy(_id) -> int: record = db.systems.find_one({"_id": _id}) if not record: raise ValueError(f"不存在_id为{_id}的系统记录") return record["energy"]
兼容方案:游标转列表后取值
如果要保留find写法,先把游标转成列表,一次性拉取所有结果后再取下标,避免动态拉取的不稳定问题:
def getEnergy(_id) -> int: records = list(db.systems.find({"_id": _id})) if len(records) == 0: raise ValueError(f"不存在_id为{_id}的系统记录") return records[0]["energy"]
额外排查项
- 打印所有调用
getEnergy时传入的_id参数的类型和值,排查是否偶发传入非法类型 - 检查MongoDB服务端日志,排查是否有连接超时、游标过期、服务端资源不足的报错
- 确认pymongo和bson库版本和服务端MongoDB版本兼容,避免版本不匹配导致的序列化bug
- 可以给查询增加最大超时时间限制,避免长时间阻塞:
find_one({"_id": _id}, max_time_ms=3000)
内容的提问来源于stack exchange,提问作者Neptune
相关产品推荐
相关产品推荐

