调用PyMongo insert_many()抛出OperationFailure而非BulkWriteError的原因
核心原因
你遇到的问题大概率是PyMongo客户端提前校验了文档BSON大小,在请求发送到MongoDB服务器之前就抛出了OperationFailure,而非等到服务器执行批量写入后返回BulkWriteError。
BSON 16MB的大小限制,PyMongo和MongoDB服务器都会做校验:
- 调用
insert_many时,PyMongo会先对每个文档做预校验,如果发现单个文档超出大小,会直接抛出OperationFailure,不会把请求发送到服务器,自然不会触发批量写入的错误逻辑,有效文档也不会被插入。 - 之前能触发
BulkWriteError,可能是当时环境中客户端未开启该预校验,或者文档大小刚好处于客户端校验阈值外但服务器拦截的范围内(这种情况极少)。
验证方式
可以手动计算每个文档的BSON编码大小,确认是否在客户端就被拦截:
import bson for idx, doc in enumerate(documents): try: encoded = bson.BSON.encode(doc) print(f"文档{idx}大小:{len(encoded)/1024/1024:.2f}MB") except bson.errors.InvalidDocument as e: print(f"文档{idx}编码失败:{e}")
如果那个20MB的文档在这一步就报错,说明是客户端预校验的问题。
解决办法
- 提前过滤超大文档
先在客户端筛选出符合BSON大小限制的文档,单独处理超大文档:
from pymongo import MongoClient
from pymongo.errors import BulkWriteError, OperationFailure
import bson
MAX_BSON_SIZE = 16 * 1024 * 1024 # 16MB
documents = [
{'x': 'a'},
{'x': 'b' * 20_000_000},
{'x': 'c'}
]
valid_docs = []
invalid_docs = []
for doc in documents:
try:
if len(bson.BSON.encode(doc)) <= MAX_BSON_SIZE:
valid_docs.append(doc)
else:
invalid_docs.append(doc)
except Exception:
invalid_docs.append(doc)
with MongoClient("mongodb://localhost:27017/") as client:
collection = client['my_db']['my_collection']
# 插入有效文档
try:
result = collection.insert_many(valid_docs, ordered=False)
print(f"成功插入{len(result.inserted_ids)}个文档")
except BulkWriteError as e:
print(f"批量写入错误:{e.details}")
# 处理无效文档(比如记录日志、拆分存储等)
if invalid_docs:
print(f"发现{len(invalid_docs)}个超出大小限制的文档")
2. **检查MongoDB服务器配置** 即使未更新版本,Docker容器重启后配置可能变化,查看MongoDB日志(`docker logs <容器名>`),确认是否有关于批量写入的错误日志,排除服务器端异常行为。 3. **确认PyMongo依赖环境** 即使没更新PyMongo版本,依赖的`bson`库可能被间接更新,执行`pip list | grep bson`查看版本,对比之前能正常复现的环境版本,若有变化可回退旧版本测试。 --- 内容的提问来源于stack exchange,提问作者SOCell

