使用discord.js v14与Mongoose开发Discord机器人Warn命令时递增数值报错
问题描述
使用discord.js v14 + 最新版Mongoose开发Discord机器人警告命令,需求是:首次警告用户时number字段设为1,再次警告同一用户时该字段自增为2,但执行命令时触发验证错误。
错误信息
错误:Warn验证失败:number:在路径"number"处,将值"{ '$inc': 1 }"(类型为Object)转换为字符串失败 at ValidationError.inspect (C:\Users\Robin\Documents\Multi-Purpose Bot\node_modules\mongoose\lib\error\validation.js:49:26) at formatValue (node:internal/util/inspect:782:19) at inspect (node:internal/util/inspect:347:10) at formatWithOptionsInternal (node:internal/util/inspect:2167:40) at formatWithOptions (node:internal/util/inspect:2029:10) at console.value (node:internal/console/constructor:332:14) at console.warn (node:internal/console/constructor:365:61) at C:\Users\Robin\Documents\Multi-Purpose Bot\Commands\Moderation\warn.js:60:40 at C:\Users\Robin\Documents\Multi-Purpose Bot\node_modules\mongoose\lib\model.js:5195:18 at processTicksAndRejections (node:internal/process/task_queues:78:11) { errors: { number: CastError: 在路径"number"处,将值"{ '$inc': 1 }"(类型为Object)转换为字符串失败 at SchemaString.cast (C:\Users\Robin\Documents\Multi-Purpose Bot\node_modules\mongoose\lib\schema\string.js:603:11) at SchemaString.SchemaType.applySetters (C:\Users\Robin\Documents\Multi-Purpose Bot\node_modules\mongoose\lib\schematype.js:1201:12) at model.$set (C:\Users\Robin\Documents\Multi-Purpose Bot\node_modules\mongoose\lib\document.js:1368:22) at model.$set (C:\Users\Robin\Documents\Multi-Purpose Bot\node_modules\mongoose\lib\document.js:1093:16) at model.Document (C:\Users\Robin\Documents\Multi-Purpose Bot\node_modules\mongoose\lib\document.js:166:12) at model.Model (C:\Users\Robin\Documents\Multi-Purpose Bot\node_modules\mongoose\lib\model.js:121:12) at new model (C:\Users\Robin\Documents\Multi-Purpose Bot\node_modules\mongoose\lib\model.js:5020:15) at Object.execute (C:\Users\Robin\Documents\Multi-Purpose Bot\Commands\Moderation\warn.js:57:27) at Object.execute (C:\Users\Robin\Documents\Multi-Purpose Bot\Events\interactions\interactionCreate.js:12:21) at Client.<anonymous> (C:\Users\Robin\Documents\Multi-Purpose Bot\Handlers\eventHandler.js:25:63) { stringValue: `"{ '$inc': 1 }"`, messageFormat: undefined, kind: 'string', value: [Object], path: 'number', reason: null, valueType: 'Object' } }, _message: 'Warn验证失败' }
问题原因
- 错误使用
$inc操作符:$inc是Mongoose的更新操作符,只能用于更新已有文档,不能直接在创建新文档时赋值给字段。你把它当成普通值传给number字段,导致Mongoose尝试把这个对象转换成字符串(因为Schema中number字段被定义为String类型),触发类型转换错误。 - 逻辑缺失:当前代码每次警告都创建新文档,没有实现“同一用户再次警告时递增
number”的核心逻辑。
修复步骤
步骤1:修正Warn Schema结构
确保../../Models/Warn.js中number字段为Number类型(支持数值递增),示例Schema:
const mongoose = require('mongoose'); const WarnSchema = new mongoose.Schema({ userId: { type: String, required: true }, reason: { type: String, required: true }, Date: { type: String, required: true }, staffId: { type: String, required: true }, number: { type: Number, required: true } }); module.exports = mongoose.model('Warn', WarnSchema);
步骤2:重构命令逻辑
- 先查询目标用户已有警告记录数,计算最新的
number值 - 首次警告时
number设为1,后续警告设为已有记录数+1 - 创建新警告文档并保存
修改后的完整命令代码
const { Client, SlashCommandBuilder, EmbedBuilder, PermissionFlagsBits } = require("discord.js"); const Schema = require("../../Models/Warn"); module.exports = { data: new SlashCommandBuilder() .setName("warn") .setDescription("Warns a member in your guild. **ADMIN**") .setDefaultMemberPermissions(PermissionFlagsBits.ModerateMembers) .addUserOption(option => option.setName("target") .setDescription("Select the user you wish to warn.") .setRequired(true) ) .addStringOption(option => option.setName("reason") .setDescription("What is the reason of the warn?") ), async execute(interaction) { const { guild, options } = interaction; const user = options.getUser("target"); const member = guild.members.cache.get(user.id); const reason = options.getString("reason") || "No reason provided"; const errEmbed = new EmbedBuilder() .setDescription('Something went wrong. Please try again later.') .setColor(0xc72c3b); const successEmbed = new EmbedBuilder() .setTitle("**:white_check_mark: Warned**") .setDescription(`Successfully warned ${user}.`) .addFields( { name: "Reason", value: `${reason}`, inline: true } ) .setColor(0x5fb041) .setTimestamp(); // 权限检查 if (member.roles.highest.position >= interaction.member.roles.highest.position) return interaction.reply({ embeds: [errEmbed], ephemeral: true }); if(!interaction.guild.members.me.permissions.has(PermissionFlagsBits.ModerateMembers)) return interaction.reply({ embeds: [errEmbed], ephemeral: true }); try { // 格式化日期 const date_ob = new Date(); const date = date_ob.getDate(); const month = date_ob.getMonth() + 1; const year = date_ob.getFullYear(); const actualDate = `${year}-${month}-${date}`; // 查询用户已有警告数量,计算新的警告编号 const existingWarns = await Schema.countDocuments({ userId: member.id }); const newWarnNumber = existingWarns + 1; // 创建新警告文档 const newWarn = new Schema({ userId: member.id, reason: reason, Date: actualDate, staffId: interaction.member.user.username, // 修正原代码中获取管理员名称的错误 number: newWarnNumber }); await newWarn.save(); console.log("New user has been warned. Saved to database."); interaction.reply({ embeds: [successEmbed], ephemeral: true }); } catch (err) { console.error(err); return interaction.reply({ embeds: [errEmbed], ephemeral: true }); } } };
额外优化说明
- 修正了原代码中
interaction.member.name的错误,改用interaction.member.user.username获取管理员用户名 - 简化日期格式化代码,直接使用
Date对象处理 - 添加
await等待文档保存完成,避免异步逻辑问题 - 在catch块中新增用户端错误反馈,提升交互体验
内容的提问来源于stack exchange,提问作者Bob Dylan
相关产品推荐
相关产品推荐

