如何在discord.js中实现quickmongo经济机器人的服务器专属排行榜
优化方案
原代码崩溃核心原因有两个:一是大服下发起了和成员数对等的海量并发数据库查询,数据库IO和进程内存直接被打满;二是无差别遍历全服成员做无效查询,大量零余额/不在经济系统内的用户占用了不必要的资源。
优化思路是从数据库侧批量拉取数据,再做服务器成员归属过滤,完全不需要遍历全服务器成员缓存,实现代码如下:
// 1. 一次性批量拉取所有有余额的用户数据,仅1次数据库请求 const allBalanceData = await db.startsWith("mon_"); // (可选)如果未开启成员缓存,先执行一次全量成员拉取:await message.guild.members.fetch() // 2. 预生成当前服务器所有成员ID的Set,判断存在性的时间复杂度为O(1) const guildMemberIds = new Set(message.guild.members.cache.map(m => m.id)); // 3. 过滤出属于当前服务器、且余额大于0的用户 const serverRichList = allBalanceData .filter(item => { const userId = item.key.split("_")[1]; return guildMemberIds.has(userId) && item.data > 0; }) .map(async item => { const userId = item.key.split("_")[1]; const nick = await db.fetch(`nick_${userId}`) || message.guild.members.cache.get(userId).user.tag; return { data: item.data, ID: nick }; }); // 等待所有昵称查询完成,并发量仅为榜单长度级,资源占用极低 const processedList = await Promise.all(serverRichList); // 4. 排序取前5 const sortedList = processedList.sort((a, b) => b.data - a.data).slice(0, 5); if (sortedList.length < 1) return message.reply('No rich people here -_-'); // 5. 拼接输出文本 let final = ""; sortedList.forEach((item, index) => { let medal = '🔹️'; if (index === 0) medal = '🥇'; else if (index === 1) medal = '🥈'; else if (index === 2) medal = '🥉'; final += `${medal} **${item.data.toLocaleString()}** - ${item.ID}\n`; }); // 后续发送final的逻辑自行补充
优化效果说明
- 数据库请求量从原来的
2*服务器成员数降低到1 + 榜单长度,大服场景下性能提升上千倍 - 完全不需要遍历全服务器成员,只处理有余额的有效用户,内存占用降低90%以上
- 修复了原代码的拼写错误
xy.lenght、数组遍历索引取值错误的问题
内容的提问来源于stack exchange,提问作者GentleScreamer
相关产品推荐
相关产品推荐

