MongoDB查询异常:Discord冒险命令仅读取首个文档数据
问题根源与修复方案
1. 核心问题:字段名大小写不匹配
你的代码中查询和更新操作的用户ID字段名大小写不一致:
- 查询用户时用的是
{ MemberId: Member.id }(字段名是MemberId,小写d) - 更新用户时用的是
{ MemberID: Member.id }(字段名是MemberID,大写D)
MongoDB对字段名大小写严格区分,这会导致:查询时的条件无法匹配到当前用户的文档,findOne会返回集合中的第一个文档(也就是你的个人档案),但更新时用对了字段名,所以结果能添加到正确用户的文档里,最终出现"用你的数据计算,给正确用户加收益"的异常。
修复:统一所有操作的字段名,比如全部改成MemberID(和更新逻辑一致):
// 将查询条件中的MemberId改为MemberID econModel.findOne({ MemberID: Member.id }, async (err, Account) => { // 后续逻辑不变 })
2. 优化更新逻辑:利用查询实例直接修改
你当前多次调用econModel.collection.updateOne,效率低且易出错。直接使用查询到的Account实例修改后保存,更可靠:
// 替换所有updateOne操作 if(nextLvl <= newExp){ Account.Level += 1; Account.Fowlercoins += coinAdd; Account.Exp += xpTotal; Account.Next = nextLvl; await Account.save(); interaction.reply({ content: `${Member.nickname}\nYou have leveled up! You are now level ${Account.Level}!\nYou gained ${xpTotal} experience and found ${coinAdd} coins.`, components: [] }); } else { Account.Fowlercoins += coinAdd; Account.Exp += xpTotal; Account.Next = nextLvl; await Account.save(); interaction.reply({ content: `${Member.nickname}\nYou gained ${xpTotal} experience and found ${coinAdd} coins.`, components: [] }); }
3. 修复异步逻辑混用问题
原代码中findOne的回调函数加了async,传统回调和async/await混用容易出现不可预期的行为,建议改用纯async/await写法,代码更清晰:
// 给execute方法加上async execute: async (interaction) => { const Member = interaction.member; const memberHasAdvCooldown = adventureCooldowns.has(Member.id); function getRandomInt(min, max) { min = Math.ceil(min); max = Math.floor(max); return Math.floor(Math.random() * (max - min)) + min; } if(memberHasAdvCooldown){ const remaining1 = adventureCooldowns.get(Member.id) - new Date(); const remainingFormatted1 = humanizeDuration(remaining1, { language: 'en', round: true, units: ['h', 'm', 's'], }) // 添加return避免后续逻辑执行 return interaction.reply({ content: `You must wait ${remainingFormatted1} for the cooldown period to end before adventuring again.`, ephemeral: true}); } try { // 改用async/await查询 const Account = await econModel.findOne({ MemberID: Member.id }); if(Account) { console.log(`ID: ${Member.id}\n${Member.nickname}`); const curXp = Account.Exp; console.log(`Current XP: ${curXp}`); const curLvl = Account.Level; console.log(`Curent Level: ${curLvl}`); const coinBonus = Account.coinBonus; console.log(`Coin Bonus: ${coinBonus}`); const xpBonus = Account.expBonus; console.log(`XP Bonus: ${xpBonus}`); const xpBase = Math.floor(Math.random() * 10 + 50); console.log(`Base XP: ${xpBase}`); const xpLvlBonus = xpBase * curLvl; console.log(`lvl XP: ${xpLvlBonus}`); const xpTotal = Math.floor(xpLvlBonus * xpBonus); console.log(`Total: ${xpTotal}`); const Coins = getRandomInt(25, 200); console.log(`Base coins: ${Coins}`); const coinAdd = Math.floor(Coins * coinBonus); console.log(`total coins: ${coinAdd}`); const nextLvl = (500 * Math.pow(2, curLvl))/2; console.log(`Next level: ${nextLvl}`); const newExp = curXp + xpTotal; if(nextLvl <= newExp){ Account.Level += 1; Account.Fowlercoins += coinAdd; Account.Exp += xpTotal; Account.Next = nextLvl; await Account.save(); interaction.reply({ content: `${Member.nickname}\nYou have leveled up! You are now level ${Account.Level}!\nYou gained ${xpTotal} experience and found ${coinAdd} coins.`, components: [] }); } else{ Account.Fowlercoins += coinAdd; Account.Exp += xpTotal; Account.Next = nextLvl; await Account.save(); interaction.reply({ content: `${Member.nickname}\nYou gained ${xpTotal} experience and found ${coinAdd} coins.`, components: [] }); } adventureCooldowns.set(Member.id, Date.now() + 5000); setTimeout(() => adventureCooldowns.delete(Member.id), 5000); } else{ // 补充导入MessageEmbed:const { MessageEmbed } = require("discord.js"); interaction.reply({ embeds: [new MessageEmbed() .setTitle("ECONOMY SYSTEM") .setColor("#3be820") .setDescription(`${interaction.member.nickname} does not have an account! To create one, use /economy start!`) .setFooter({ text: 'Rum Bot 1.4.5' })] }); } } catch(err) { console.error(err); return interaction.reply({ content: "An error occurred while processing your request.", ephemeral: true }); } }
4. 其他小修复
- 补充
MessageEmbed的导入:在顶部添加const { MessageEmbed } = require("discord.js"); - 给冷却判断分支添加
return,避免用户在冷却中仍执行后续查询逻辑 - 建议在
econModel的Schema中给MemberID添加唯一索引,防止重复创建用户档案:
// 在econModel的schema定义里 MemberID: { type: String, required: true, unique: true }
内容的提问来源于stack exchange,提问作者Michael Peterson
相关产品推荐
相关产品推荐

