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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.03 06:15:02