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

Discord机器人重启后排行榜重置仅显示缓存用户的解决方法

问题根因

你的排行榜数据本身持久化存储在UserModel对应的数据库中,机器人重启不会造成数据丢失。出现“仅展示重启后使用过机器人的用户”问题,是现有代码的两处逻辑缺陷导致的:

  • 筛选服务器有效成员时,仅判断用户ID是否存在于message.guild.members.cache本地缓存中。Discord.js默认不会在启动时预加载全服务器成员到缓存,只有触发过交互、发过消息的用户才会进入缓存,因此刚重启时缓存数据不全
  • 生成排行榜描述的循环中,只要遇到一个不在缓存的上榜用户,就直接执行return终止整个渲染逻辑,直接导致后续内容无法正常输出
修复方案

前置配置

首先需要开启成员拉取权限:

  1. 打开Discord开发者后台,进入你的机器人应用的「Bot」配置页
  2. 在Privileged Gateway Intents分组下,打开Server Members Intent开关并保存
  3. 在机器人客户端初始化代码中,添加GuildMembers到intents配置列表,确保有权限拉取全量服务器成员

代码修正

核心改动点:

  • 进入排行榜逻辑后,先主动拉取当前服务器全量成员到缓存,不依赖启动时的默认缓存
  • 用Set结构做成员存在性判断,提升大服务器下的运行性能
  • 移除循环中遇到不存在用户就直接终止逻辑的写法,对已退出服务器的用户做降级展示
  • 初始化描述变量为空字符串,解决你提到的内容开头出现undefined的问题

修正后的完整核心代码如下:

// 主动拉取当前服务器全量成员,强制刷新本地缓存
await message.guild.members.fetch();
const allUserData = await UserModel.find({});
const validMembers = [];
// 用Set存储服务器成员ID,存在性判断性能远高于数组includes
const guildMemberIdSet = new Set(message.guild.members.cache.map(member => member.id));
for (const userData of allUserData) {
  if (guildMemberIdSet.has(userData.ID)) validMembers.push(userData);
}

const rankEmbed = new MessageEmbed()
  .setTitle(`${message.guild.name}'s Leaderboard`)
  .setFooter({
    text: `You aren't ranked yet!`,
    iconURL: message.author.displayAvatarURL({ dynamic: true }),
  });

// 按余额降序排序,过滤余额为0的用户
const sortedMembers = validMembers
  .sort((a, b) => b.Money - a.Money)
  .filter(user => user.Money > 0);

// 计算当前用户排名
let currentUserRank = 0;
for (let i = 0; i < sortedMembers.length; i++) {
  if (sortedMembers[i].ID === message.author.id) {
    currentUserRank = i + 1;
    rankEmbed.setFooter({
      text: `You are ranked ${currentUserRank} in the leaderboard!`,
      iconURL: message.author.displayAvatarURL({ dynamic: true }),
    });
    break;
  }
}

// 取前10名生成排行榜描述
const top10Members = sortedMembers.slice(0, 10);
let description = '';
for (let i = 0; i < top10Members.length; i++) {
  const memberData = top10Members[i];
  const guildMember = message.guild.members.cache.get(memberData.ID);
  const balance = Math.round(memberData.Money);
  // 对已退出服务器的用户做降级展示,不中断整体渲染
  const displayName = guildMember ? guildMember.user.tag : `已退出用户(ID: ${memberData.ID})`;
  description += `${i + 1}. ${displayName} - $${balance}\n`;
}

rankEmbed.setDescription(description);
rankEmbed.setColor("RED");
message.reply({ embeds: [rankEmbed] });

额外优化说明

如果你的服务器成员规模超过10万,不建议每次调用排行榜都全量拉取成员,可以在用户每次触发指令、发送消息时主动更新对应成员的缓存,或者单独维护一份成员ID-用户名的映射表存在数据库中,进一步降低接口请求耗时。

内容的提问来源于stack exchange,提问作者FSCYT

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.01 04:39:57