Discord.js命令冷却到期后如何自动删除数据库过期记录
Discord 机器人命令冷却记录自动删除实现方案
现有代码核心问题
- 查到数据库存在冷却记录时,没有先校验记录的过期时间,哪怕冷却已经结束,仍会向用户返回冷却中提示
- 重复调用两次
findOne查询同一条冷却记录,属于冗余操作,第一次查询返回的data对象就是目标记录,无需二次查询 - 你编写的过期记录删除片段逻辑本身正确,但原有代码分支没有给过期记录预留处理入口,查到记录就默认判定为冷却中直接返回,因此找不到合适的插入位置
修正后逻辑说明
你写的删除代码需要放在查询到冷却记录的分支最开头,优先判断记录是否过期:
- 如果记录已过期:先删除旧的过期记录,再正常执行命令、写入新的冷却记录
- 如果记录未过期:再计算剩余冷却时间,向用户返回冷却提示
修正后的完整可运行代码如下:
const cmd = client.commands.get(command) || client.commands.find(a => a.aliases && a.aliases.includes(command)) if(cmd) { if(cmd.cooldown) { const cools = require("./Schema/cooldown"); cools.findOne({ guildID: message.guild.id, userID: message.author.id, command: cmd.name }, async(err, data) => { if(data) { const timeLeft = data.coolDown - Date.now(); // 冷却已过期,删除旧记录后正常执行命令 if(timeLeft <= 0) { await cools.findOneAndRemove({ guildID: message.guild.id, userID: message.author.id, command: cmd.name }) cmd.execute(client, message, args, prefix) new cools({ guildID: message.guild.id, userID: message.author.id, coolDown: Date.now() + cmd.cooldown, command: cmd.name }).save(); return } // 冷却未过期,返回提示 const remainingTime = ms(timeLeft, {long: true}) const embed = new MessageEmbed() .setDescription(`You already used ${cmd.name} command.`) .addField("Cooldown Time:", `${remainingTime}`) .setColor('RANDOM') .setTimestamp() return message.channel.send({embeds: [embed]}) } else { // 无冷却记录,直接执行命令并写入冷却 cmd.execute(client, message, args, prefix) new cools({ guildID: message.guild.id, userID: message.author.id, coolDown: Date.now() + cmd.cooldown, command: cmd.name }).save(); } }) } }
优化建议
- 上述实现属于懒删除机制,只有用户触发对应命令时才会检查并删除过期记录,不需要额外维护定时器,内存开销极低,是Discord机器人冷却功能的主流实现方式
- 如果担心长期运行后数据库堆积大量无人触发的过期记录,可以在机器人的
ready事件中添加定时批量清理任务,每小时清理一次全库过期记录即可:
// 写入机器人ready事件回调中 setInterval(async () => { const cools = require("./Schema/cooldown"); // 批量删除所有到期的冷却记录 await cools.deleteMany({ coolDown: { $lt: Date.now() } }) }, 3600000) // 间隔1小时,单位毫秒
- 不要为每条冷却记录单独创建
setTimeout做定时删除:机器人重启时所有内存中的定时器会全部失效,且用户量级较大时会占用大量内存,极易引发内存泄漏。
内容的提问来源于stack exchange,提问作者エース
相关产品推荐
相关产品推荐

