You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 20:45:31