使用PyMongo在for循环插入字典报InvalidDocument错误求助
嘿,我来帮你排查这个问题!你遇到的InvalidDocument: Cannot encode object: 1509261251错误,核心原因大概率是循环里生成的字典中,某个值的类型不是PyMongo能直接序列化的——哪怕你单独插同一个字典能成功,循环内的上下文可能悄悄改变了数据类型。
为什么会出现这个问题?
看报错里的数字1509261251,它很可能不是Python原生的int类型,而是pandas常用的numpy数值类型(比如numpy.int64)。PyMongo默认只支持序列化Python原生的数据类型,不认识numpy的数值类型,但你单独测试的时候,可能无意中把它转成了原生int(比如手动复制数值时自动转换),所以能插入成功。
再看你的代码,循环里用sportModel和healthyModel生成预测值后,直接赋值给了DataFrame的列。很多机器学习模型(比如sklearn的模型)返回的结果是numpy数组/数值,直接存在DataFrame里后,这些值的类型还是numpy类型,后续你从DataFrame里取出构建字典插入MongoDB时,就带着这个不被支持的类型了。
解决方法
这里给你两个实用的方案:
方案1:手动转换为Python原生类型
在构建插入的字典时,把numpy类型的数值转成Python原生的int或float:
for i in range(len(re_kw)): kw = re_kw.iloc[i]['keywords'] # 生成预测值并转成原生类型 sport_pred = int(sportModel([kw])[0]) healthy_pred = int(healthyModel([kw])[0]) # 更新DataFrame(可选,如果你需要保留转换后的值) re_kw.loc[re_kw['_id'] == re_kw.iloc[i]['_id'], '1'] = sport_pred re_kw.loc[re_kw['_id'] == re_kw.iloc[i]['_id'], '5'] = healthy_pred # 构建要插入的字典 doc = { "_id": re_kw.iloc[i]['_id'], "keywords": kw, "1": sport_pred, "5": healthy_pred # 其他字段同理 } # 插入MongoDB your_collection.insert_one(doc)
或者如果你想一次性转换DataFrame里的所有数值列,可以用astype:
# 把DataFrame里的数值列转成Python原生类型 re_kw[['1', '5']] = re_kw[['1', '5']].astype(int)
方案2:定制PyMongo编码器(一劳永逸)
如果你经常需要插入numpy类型的数据,可以自定义一个编码器,让PyMongo自动处理:
from bson import json_util import numpy as np import pymongo def numpy_encoder(obj): if isinstance(obj, np.integer): return int(obj) elif isinstance(obj, np.floating): return float(obj) elif isinstance(obj, np.ndarray): return obj.tolist() # 其他类型交给默认编码器处理 return json_util.default(obj) # 创建MongoClient时指定这个编码器 client = pymongo.MongoClient( "your_mongodb_uri", json_options=pymongo.json_util.JSONOptions(default=numpy_encoder) )
这样之后不管是循环里还是循环外插入,PyMongo都会自动把numpy类型转成支持的原生类型。
为什么循环外单独插没问题?
大概率是你单独测试时,手动复制的数值已经被自动转换成了Python原生int,或者DataFrame在循环外经过了某些操作(比如重新读取、类型转换),导致数值类型发生了变化,所以插入时没有报错。
内容的提问来源于stack exchange,提问作者Ken Hsieh

