Discord.js v13+MongoDB环境messageCreate事件prefix读取报错修复
问题根本原因
你混用了Mongoose的await异步语法和回调函数语法,导致首次查询不到服务器数据时,settings变量被赋值为null,后续读取settings.prefix时触发空指针错误。具体执行逻辑如下:
- 机器人刚进服务器时数据库没有对应记录,
Guild.findOne返回null - 你在回调函数中创建并保存了新的服务器配置,但回调的返回值不会赋值给外层的
settings变量 - 代码不等保存逻辑执行完成就继续向下运行,直接读取
null.prefix触发崩溃 - 重启后数据已经存入数据库,查询能拿到有效对象,功能就恢复正常
修复方案
统一使用async/await语法处理数据库操作,判断查询结果为空时手动创建配置对象并等待保存完成,保证settings变量永远有有效值,修改后的完整代码如下:
// MODULES const Discord = require('discord.js'); const mongoose = require('mongoose'); const Levels = require('discord.js-leveling'); // FILES const Guild = require('../../models/guild'); const config = require('../../files/config.json'); const swearwords = require("../../files/data.json"); const colors = require('../../files/colors.json'); // ERROR MESSAGE const errorMain = new Discord.MessageEmbed() .setDescription("出现错误!") .setColor(colors.COLOR) const addedDatabase = new Discord.MessageEmbed() .setDescription("该服务器已成功添加到我们的数据库。") .setColor(colors.COLOR) module.exports = async (Discord, client, message) => { if (!message.guild) return; if (message.author.bot) return; // 替换原有findOne查询逻辑 let settings = await Guild.findOne({ guildID: message.guild.id }).catch(err => message.channel.send(errorMain)); if (!settings) { // 不存在对应服务器配置时直接创建 settings = new Guild({ _id: mongoose.Types.ObjectId(), guildID: message.guild.id, prefix: config.PREFIX, logChannelID: String, enableLog: false, enableSwearFilter: true, enableMusic: true, enableLevel: true, }); // 等待保存完成再执行后续逻辑 await settings.save().catch(err => message.channel.send(errorMain)); message.channel.send({embeds: [addedDatabase]}).then(m => m.delete({ timeout: 10000 })); } // VARIABLES const IDGuild = message.guild.id; const user = message.author; const prefix = settings.prefix; const swearFilterOn = settings.enableSwearFilter; // LEVEL SYSTEM if (settings.enableLevel) { const randomAmountOfXp = Math.floor(Math.random() * 29) + 1; const hasLeveledUp = await Levels.appendXp(message.author.id, message.guild.id, randomAmountOfXp); if (hasLeveledUp) { const userLevel = await Levels.fetch(message.author.id, message.guild.id); const levelEmbed = new Discord.MessageEmbed() .setTitle('等级提升!') .setColor(colors.COLOR) .setDescription(`**太棒了** ${message.author},你刚刚升级到**${userLevel.level}**级! 继续聊天就能继续升级哦。`) message.channel.send({embeds: [levelEmbed]}); } } // EXECUTE COMMAND AND SWEARFILTER if (swearFilterOn) { var msg = message.content.toLowerCase(); for (let i = 0; i < swearwords["swearwords"].length; i++) { if (msg.includes(swearwords["swearwords"][i])) { message.delete(); return message.channel.send("请不要发送脏话。").then(msg => msg.delete({ timeout: 3000 })); } } } if (!message.content.startsWith(prefix) || message.author.bot) return; const args = message.content.slice(prefix.length).split(/ +/); const cmd = args.shift().toLowerCase(); const command = client.commands.get(cmd) || client.commands.find(a => a.aliases && a.aliases.includes(cmd)); if (command) command.execute(client, message, args, Discord) }
额外优化说明
- 移除了重复的命令解析逻辑,无需在脏话过滤的两个分支里写两遍相同代码
- 修正了布尔值判断逻辑,你存储的
enableLevel、enableSwearFilter是布尔类型,原来和字符串"true"对比会永远返回false,导致等级系统、脏话过滤功能不生效 - 统一所有异步操作加await等待完成,避免逻辑时序错误
内容的提问来源于stack exchange,提问作者QuaBot
相关产品推荐
相关产品推荐

