Discord票务机器人/add命令功能异常求助:Mongoose字段类型冲突导致报错
Fixing the
/add Command Crash in Your Discord Ticket Bot Let's break down why your /add command is crashing and walk through the fixes step by step.
Root Cause of the Issues
Your problems stem from a mismatch between the MembersID field type in your Mongoose Schema and the data already stored in your database:
- When
MembersIDwas a String: You tried calling.push()on a string value, which isn't a valid method for strings—hence theis not a functionerror. - When you switched to an Array: Existing documents in your DB still had
MembersIDstored as a string, so MongoDB threw a type mismatch error when trying to process those old entries.
Step 1: Fix the Mongoose Schema
First, update your Ticket.js Schema to enforce MembersID as an array of strings, and set a default empty array to ensure new tickets start with valid data:
module.exports = model("Tickets", new Schema({ GuildID: String, MembersID: { type: [String], default: [] // Critical: ensures new tickets have an empty array instead of undefined/string }, TicketID: String, ChannelID: String, Closed: Boolean, Locked: Boolean, Type: String, Claimed: Boolean, ClaimedBy: String }));
Step 2: Migrate Existing Ticket Data
You need to convert all old MembersID string values in your database to arrays. Add this migration script to run when your bot starts up:
const Ticket = require('./Structures/Schemas/Tickets'); async function migrateOldTickets() { try { // Find all tickets where MembersID is still a string const oldTickets = await Ticket.find({ MembersID: { $type: "string" } }); for (const ticket of oldTickets) { let membersArray; // Handle cases where the string might have comma-separated IDs if (ticket.MembersID.includes(',')) { membersArray = ticket.MembersID.split(',').map(id => id.trim()); } else { // Convert single ID string to a single-element array membersArray = ticket.MembersID ? [ticket.MembersID] : []; } ticket.MembersID = membersArray; await ticket.save(); } console.log('✅ Old ticket data migrated successfully'); } catch (err) { console.error('❌ Error migrating ticket data:', err); } } // Run migration after bot is ready client.once('ready', async () => { await migrateOldTickets(); console.log('🚀 Bot is online and ready'); });
Step 3: Update the /add and /remove Command Logic
Rewrite your command logic to use async/await (instead of callbacks) for better error handling, and ensure proper array operations:
const { MessageEmbed, CommandInteraction} = require("discord.js"); const DB = require("../../Structures/Schemas/Tickets"); module.exports = { name: "actions", description: "Ticket Actions.", permission: "ADMINISTRATOR", options: [ { name: "action", type: "STRING", description: "Add or Remove a member from this ticket.", required: true, choices: [ { name: "Add", value: "add" }, { name: "Remove", value: "remove" }, ], }, { name: "member", description: "Select the Member(s)", type: "USER", required: true, }, ], /** * @param {CommandInteraction} interaction */ async execute(interaction) { const { guildId, options, channel } = interaction; const Action = options.getString("action"); const Member = options.getMember("member"); const Embed = new MessageEmbed(); try { switch(Action) { case "add": const addTicket = await DB.findOne({ GuildID: guildId, ChannelID: channel.id }); if (!addTicket) { return interaction.reply({ embeds: [Embed.setColor("#5104DB").setDescription("⛔ | This channel is not tied with a ticket.")], ephemeral: true, }); } if (addTicket.MembersID.includes(Member.id)) { return interaction.reply({ embeds: [Embed.setColor("#5104DB").setDescription("⛔ | This member has already been added to this ticket.")], ephemeral: true, }); } // Add member to the array addTicket.MembersID.push(Member.id); // Update channel permissions await channel.permissionOverwrites.edit(Member.id, { SEND_MESSAGES: true, VIEW_CHANNEL: true, READ_MESSAGE_HISTORY: true, }); await addTicket.save(); await interaction.reply({ embeds: [Embed.setColor("#5104DB").setDescription(`✅ | ${Member} has been added to this ticket.`)], }); break; case "remove": const removeTicket = await DB.findOne({ GuildID: guildId, ChannelID: channel.id }); if (!removeTicket) { return interaction.reply({ embeds: [Embed.setColor("#5104DB").setDescription("⛔ | This channel is not tied with a ticket.")], ephemeral: true, }); } if (!removeTicket.MembersID.includes(Member.id)) { return interaction.reply({ embeds: [Embed.setColor("#5104DB").setDescription("⛔ | This member is not associated with this ticket.")], ephemeral: true, }); } // Remove member from the array (filter is cleaner than .remove()) removeTicket.MembersID = removeTicket.MembersID.filter(id => id !== Member.id); // Update channel permissions await channel.permissionOverwrites.edit(Member.id, { VIEW_CHANNEL: false, }); await removeTicket.save(); await interaction.reply({ embeds: [Embed.setColor("#5104DB").setDescription(`✅ | ${Member} has been removed from this ticket.`)], }); break; } } catch (err) { console.error(`Error handling ${Action} action:`, err); await interaction.reply({ embeds: [Embed.setColor("#FF0000").setDescription("❌ | An error occurred while processing this action.")], ephemeral: true, }); } }, };
Key Improvements in This Fix
- Error Handling: Wrapped all logic in a
try/catchblock to prevent bot crashes and provide user-friendly error messages. - Async/Await: Replaced callback functions with
async/awaitfor cleaner, more readable code. - Array Operations: Used valid array methods (
push,filter) instead of invalid string methods. - Data Consistency: Ensured all existing and new tickets use the correct array type for
MembersID.
内容的提问来源于stack exchange,提问作者senpai
相关产品推荐
相关产品推荐

