Pymongo存储数据报错InvalidDocument: cannot encode object问题求助
问题排查与修复方案
核心报错根因
你遇到的InvalidDocument: cannot encode object报错,本质是MongoDB只能序列化JSON支持的基础类型(整数、字符串、字典、列表等),无法直接序列化自定义对象或非法数据结构,你的代码里同时存在两类触发该错误的问题,还有其他语法逻辑错误。
具体问题说明
- 问题1:
on_ready方法中post变量定义错误
你写的post是两个字典用逗号分隔,实际会被Python识别为元组类型,而insert_one方法要求传入单个字典类型的文档,直接传入元组会触发序列化失败。 - 问题2:直接存储
discord.Role自定义对象add_shop方法中你直接把discord.Role类型的role参数存入MongoDB,PyMongo无法对discord的自定义角色对象做序列化,因此抛出编码错误,正确做法是存储角色的唯一ID(整数类型)。 - 问题3:
shop方法查询语法错误
你写的self.collection.find_one({"_id": ctx.author.id}["role"])是错误语法,会直接在查询条件字典里找role键(不存在)触发KeyError,正确逻辑是先查询到完整文档,再从文档里提取对应字段。 - 其他小问题:
add_shop方法中添加反应的代码缩进错误,不在函数体内,无法执行;同一文档的两次更新可以合并为一次,减少数据库请求。
修正后的代码示例
第一段(on_ready部分)
@Bot.event async def on_ready(): await Bot.change_presence(status = discord.Status.online, activity = discord.Streaming(name = '!help', url = '')) print(Bot.user.name + " is ready.") for guild in Bot.guilds: for member in guild.members: # 合并为单个字典,不要用逗号分隔成两个字典 post = { "_id": member.id, "server_id": guild.id, "balance": 300, "xp": 0, "lvl": 1, "role": 0, "cost": 0 } if collection.count_documents({"_id": member.id}) == 0: collection.insert_one(post)
第二段(命令部分)
@commands.command() async def add_shop(self, ctx, role: discord.Role, cost: int): # 存role的id而非role对象,合并两次更新为一次 self.collection.update_one( {"_id": ctx.author.id}, {"$set": {"role": role.id, "cost": cost}} ) # 修正缩进,放到函数体内 await ctx.message.add_reaction("✅") @commands.command() async def shop(self, ctx): # 先查完整文档,再提取字段 user_doc = self.collection.find_one({"_id": ctx.author.id}) r = user_doc["role"] c = user_doc["cost"] # 如果需要显示角色名,可以取消下方注释从服务器取role对象再输出 # role_obj = ctx.guild.get_role(r) await ctx.send(r, c)
内容的提问来源于stack exchange,提问作者Den
相关产品推荐
相关产品推荐

