MongoDB findOneAndDelete() will not delete the specified query-- I can't quite figure out why? - javascript

I'm trying to write a Discord.JS bot that lists and removes specific channels/threads using MongoDB's Model and Schema functionality. I've gotten everything else figured out, the actual message deletion, channel deletion, and everything else I needed for the remove function, but for some reason prompting MongoDB to delete the ChatListing schema using ids specified doesn't work.
case 'remove':
modal.setTitle('Remove a Listing');
const listingIDInput = new TextInputBuilder()
.setCustomId('listingIDInput')
.setLabel(`What's the ID of your listing?`)
.setPlaceholder('EX... 14309')
.setMinLength(5)
.setStyle(TextInputStyle.Short)
.setRequired(true);
const rmrow = new ActionRowBuilder().addComponents(listingIDInput);
modal.addComponents(rmrow);
await interaction.showModal(modal);
try {
await interaction.awaitModalSubmit({ time: 120_000 }).then( (interaction) => {
const listingToRemove = interaction.fields.getTextInputValue('listingIDInput');
ChatListing.findOne({ GuildID: guild.id, ListingID: listingToRemove }, async(err, data) =>{
if(err) throw err;
if(!data) return;
if(data.MemberID == member.id) {
const channel = await guild.channels.cache.get(data.Channel);
const msg = await channel.messages.fetch(data.MessageID);
msg.delete();
var id = data._id;
ChatListing.findByIdAndDelete({_id: mongoose.Types.ObjectId(id)});
embed.setTitle('Listing successfully removed.')
.setColor('Green')
.setDescription('⚠️ | Your chat listing has been removed successufully. We\'re sorry to see it go! | ⚠️')
.setTimestamp();
await interaction.reply({ embeds: [embed], ephemeral: true });
} else {
embed.setTitle('You aren\'t the owner of the listing!')
.setColor('Red')
.setDescription('You aren\'t capable of removing this listing because you aren\'t the user that posted it.')
.setTimestamp();
await interaction.reply({ embeds: [embed], ephemeral: true });
}
});
});
} catch (err) {
console.error(err);
}
break;
This is just the snippet in the switch case used for the slash command I've built around this functionality, and the case for listing removal.
It doesn't cause any errors in the console, however when I check the database, the test listing I put up is still there and doesn't seem to go.
Is there anything I'm doing wrong? Wherever I've looked I can't quite seem to find anything that solves this problem for me. Is the reason it's not working because it's listed within a ChatListing.findOne() function? If so, how can I modify it to work outside of that function and still keep the removal functionality?

Try using findOneAndDelete and use the returned Promise to handle success or failure:
ChatListing.findOneAndDelete({_id: mongoose.Types.ObjectId(id)})
.then(() => {
embed.setTitle('Listing successfully removed.')
.setColor('Green')
.setDescription('⚠️ | Your chat listing has been removed successufully. We\'re sorry to see it go! | ⚠️')
.setTimestamp();
interaction.reply({ embeds: [embed], ephemeral: true });
})
.catch(error => {
console.error(error);
});

Related

Edit is not a function

Trying to make a discord bot that will send a message to a specific channel on startup. I have the message sent to the specific channel on startup, however, when I try to edit it a error is thrown saying message.edit is not a function. I am following the direct steps from the documentation and it is not working. Why and how do I fix this issue?
let message: any;
if (isTextChannel(channel) && !isStageChannel(channel)) {
message = channel.send({ embeds: [ playerCountEmbedLoading() ] });
}
setInterval(() => {
if (isTextChannel(channel) && !isStageChannel(channel)) {
return message.edit({ embeds: [ playerCountEmbed() ] })
}
You're not awaiting the promise returned from sending the message.
message = await channel.send({ embeds: [ playerCountEmbedLoading() ] });
Source
Documentation
You should do type checking before defining the message. In this example I will use a typegaurd to filter out non text based channels.
Also, Channel.send() returns a promise containing the sent message. You need to await the promise.
import { ChannelTypes } from "discord.js";
if (channel.type !== ChannelTypes.GuildText) return console.warn("Channel is not a text channel");
let message = await channel.send({ embeds: [ playerCountEmbedLoading() ] });
setInterval(async() => {
try {
await message.edit({ embeds: [ playerCountEmbed() ] })
} catch (err) {
console.error(err);
}
}, ...);
Lastly, why use TypeScript if you're going to type a variable as any when you know exactly what it needs to be? Take advantage of the language you utilize by typing your variables.
import type { Message } from "discord.js";
let message: Message;

How do I check if a user has their DM's open? | discord.js v 14

I am making a bot that can dm a user. If the dm's of the user are off it says the message is successfully sent but in the console it returns an error.
So, what can I do to check if a user's dm is open?
The code I'm trying to run:
const rec = interaction.options.getUser('user')
const user = interaction.user.id
try {
rec.send({ embeds:[ new EmbedBuilder().setDescription(`<#${user}> says to you: ${message} `).setColor("#f05c51")
.then(interaction.reply(({ content: 'Successfully sent', ephemeral: true })))
] })
} catch (error) {
interaction.reply(({ content: `Could not send message, maybe dm's off? -> ${error}`, ephemeral: true }))
}
You can't. You need to use .catch()
rec.send({ embeds: [YOUREMBED] })
.then(message => console.log(`Sent message: ${message.content}`))
.catch(console.error);
I used unhandledRejection to know if my bot can't send a message to a specific user, also can use it all of unhandledRejection errors
process.on('unhandledRejection', async(error) => {
const admin = client.channels.cache.get('-----')
const embed = new MessageEmbed()
.setDescription(`\`\`\`\j\s\n${error.message || error.name || error }\n\`\`\``)
.setColor('RANDOM')
.setTimestamp()
admin.send({embeds: [embed]})
console.log(error)
});
You can also try it on your code.

DJS - Edit the embed when someone reacts with specific emoji

What I'm trying to do is to change the color of an embed when someone adds a reaction.
The struggle I'm currently facing is making it the if statement fire. So haven't gotten very far.
I'm also probably not targeting any specific embed. As the embed (suggestionsEmbed) has been sent multiple times.
EDIT: Updated with current code. This is working except for one thing. No embed other than the last sent can be edited. See what I mean here.
// SUGGESTIONS EMBED - BEGINS
var suggestionsEmbed;
client.on('messageCreate', async message => {
if (message.channel.id === channelSuggestions && !message.author.bot) {
db.add('counterP.plus', 1);
const embed = new MessageEmbed()
.setColor('#f9db73')
.setTitle(`Suggestion #${await db.fetch('counterP.plus') + await db.fetch('counterM.minus')}`)
.setDescription(message.content)
.setAuthor({ name: message.author.username, iconURL: message.author.displayAvatarURL() })
.setTimestamp()
.setFooter({ text: message.author.id });
suggestionsEmbed = await message.channel.send({ embeds: [embed] })
suggestionsEmbed.react('👍')
suggestionsEmbed.react('👎');
message.delete({ timeout: 0 });
console.log(db.fetch('counterP.plus'));
}
})
// SUGGESTIONS EMBED - ENDS
// CHANGE EMBED COLOR - BEGINS
const suggestionsApproved = '🟢';
const suggestionsDenied = '🔴';
client.on('messageReactionAdd', (reaction, user) => {
if (reaction.message.channel.id === channelSuggestions) {
if (reaction.emoji.name === suggestionsApproved && reaction.message.id === suggestionsEmbed.id) {
const suggestionsEmbedApproved = new MessageEmbed(suggestionsEmbed.embeds[0]).setColor('#76de51')
suggestionsEmbed.edit({ embeds: [suggestionsEmbedApproved] });
}
}
})
After the introduction of discord.js v13, you need intents declared in your bot. They were introduced so that developers could choose which types of events their bot wanted to receive. You can learn more about Intents here => Gateway Intents. First, you have to add the GUILD_MESSAGE_REACTIONS intent in your client by using:
const { Client, Intents } = require('discord.js')
const client = new Client({
intents: [
Intents.FLAGS.GUILDS,
Intents.FLAGS.GUILD_MESSAGES,
Intents.FLAGS.GUILD_MESSAGE_REACTIONS
]
})
Then after that, you can just use your original code to do whatever you want. Although you might get an error saying DiscordAPIError: Invalid Form Body embeds[0].description: This field is required, so to fix that, all you have to do is add the .setDescription() to your edited embed and then send it. Your final code might look something like this:
const { Client, Intents, MessageEmbed } = require('discord.js')
const client = new Client({
intents: [
Intents.FLAGS.GUILDS,
Intents.FLAGS.GUILD_MESSAGES,
Intents.FLAGS.GUILD_MESSAGE_REACTIONS
]
})
const suggestionsApproved = '🟢';
const suggestionsDenied = '🔴';
const channelSuggestions = 'your channel id'
client.on('messageReactionAdd', (reaction, user) => {
if (reaction.message.channel.id === channelSuggestions) { // Check if the reaction was in a particular channel
if (reaction.emoji.name === suggestionsApproved) { // Check which emoji was selected
const suggestionsEmbedApproved = new MessageEmbed()
.setColor('your color')
.setDescription('your description');
suggestionsEmbed.edit({ embeds: [suggestionsEmbedApproved]});
}
}
})
Edit
In response to the new question, here is the answer:
Instead of naming the embed as suggestionsEmbed, the correct way to do it would be to first create an embed with a different name and then use const suggestionsEmbed = await message.channel.send({ embeds: [embedName] }) so that the code will be like:
const embed = new MessageEmbed()
.setTitle('title')
.setDescription('description')
.setColor('color')
const suggestionsEmbed = await message.channel.send({
embeds: [embed]
})
Second Edit
Since you are already using await message.channel.send(), you don't have to use .then(). All you have to do is change this:
const suggestionsEmbed = await message.channel.send({ embeds: [embed] }).then(sentEmbed => {
sentEmbed.react("👍")
sentEmbed.react("👎")
});
to this:
const suggestionsEmbed = await message.channel.send({ embeds: [embed] })
suggestionsEmbed.react('👍')
suggestionsEmbed.react('👎')
Editing the Embed:
Use:
const suggestionsEmbedApproved = new MessageEmbed(suggestionsEmbed.embeds[0]).setTitle('asdfasdf')
suggestionsEmbed.edit({ embeds: [suggestionsEmbedApproved] });
So your code is trying to edit the embed rather than the message that the embed is in, (weird I know) but this should work for you.
Discord intents may vary based on your coding but should look similiar
const client = new Client({
intents: [Intents.FLAGS.GUILDS, Intents.FLAGS.GUILD_MESSAGES, Intents.FLAGS.GUILD_MESSAGE_REACTIONS],
partials: ['MESSAGE', 'CHANNEL', 'REACTION'],
})
It should be able to pick up those reactions with the below.
const suggestionsApproved = 'insertReactionEmojiName'
const suggestionsDenied = 'insertReactionEmojiName'
const channelSuggestions = 'yaddayadda'
// I would use a different emoji, one that you can get an name from like this
// 👍 which in discord is named :thumbsup:
client.on('messageReactionAdd', (reaction, user) => {
if (reaction.partial) {
// If the message this reaction belongs to was removed, the fetching might result in an API error which should be handled
try {
await reaction.fetch();
} catch (error) {
console.error('Something went wrong when fetching the message:', error);
// Return as `reaction.message.author` may be undefined/null
return;
}
}
const targetMessage = reaction.message
const channel = targetMessage.channel
if (channel.id === channelSuggestions) {
if (reaction.emoji.name === suggestionsApproved) {
const suggestionsEmbedApproved = new MessageEmbed()
.setColor('#1dce1d')
targetMessage.edit({
embeds: [suggestionsEmbedApproved]
})
console.log('fired!')
}
}
})
To edit any embed which was reacted to instead of only the previous sent one, you can use:
const suggestionsEmbedApproved = new MessageEmbed(reaction.message.embeds[0]).setColor("Your color")
reaction.message.edit({ embeds: [suggestionsEmbedApproved] });

discord.js give role when react - no reply error in the discord server

I wanted do a discord bot, and wanted it to give a role when someone reacts with an emoji, but it doesn't responsed.
My code, for now, looks like this:
client.on('messageReactionAdd', async (reaction, user) => { //here the bot adds the reaction
if (reaction.partial) {
try {
await reaction.fetch()
} catch (error) {
return console.error('error');
}
}
const guild = client.guilds.cache.get("server-id");
const role = guild.roles.cache.get("role-id");
const member = reaction.message.guild.member(user);
if (reaction.message.id !== 'text-message-id') return;
else if(reaction.emoji.name === "😎") {
if (member.roles.cache.has(fem)) return;
else
member.roles.add(role)
}
})
and
client.on('messageReactionRemove', async (reaction, user) => { //here the bot removes the reaction
if (reaction.partial) {
try {
await reaction.fetch()
} catch (error) {
console.error('error')
return
}
}
const guild = client.guilds.cache.get("server-id");
const role = guild.roles.cache.get("role-id")
const member = reaction.message.guild.member(user)
if (reaction.message.id !== 'text message id') return
else if (reaction.emoji.name === "😎") {
if (member.roles.cache.has(fem))
member.roles.remove(role)
}
});
I don't know what happened, but I thing has a version error (of
discord.js) Someone can help me?
I wanted to a RPG server, when the player reacts to a emoji, a role
of Wizard or Warrior is add...
I can't say for sure if it will fix your error, but here's a few things you should apply to your code:
Make sure you enabled partials in your startup file:
const { Client } = require('discord.js');
const client = new Client({ partials: ['MESSAGE', 'CHANNEL', 'REACTION'] });
Check if user is partial:
if(user.partial) await user.fetch();
Restructure your try block:
try {
if(reaction.partial) await reaction.fetch();
if(user.partial) await user.fetch();
}
Await the role to be added:
if (reaction.message.id !== 'text-message-id') return;
else if(reaction.emoji.name === "😎") {
if (member.roles.cache.has(fem)) return;
else await member.roles.add(role);
}
You have to await this, because roles.add() returns a promise
Also...
if you're planning to add some more messages / reactions you can use a switch for this.
Example:
// Listen for messages
switch(reaction.message.id) {
case 'your message id':
if(reaction.emoji.name === '👍') {
// Your code, if the user reacted with 👍
}
break;
case 'another message id':
// if you want to listen for multiple reactions, you can add a switch for that
// too
switch(reaction.emoji.name) {
case '😂':
// your code if user reacted with 😂
break;
case '❌':
// your code if user reacted with ❌
break;
default:
break;
}
default:
break;
}
Note:
Of course you don't have to use a switch / switches because for some people it's a bit confusing / not clean. You can manage this with if / if else statements too, but if this is getting more and more I'd recommend using a switch
The rest of your code looks fine, so I hope this will fix your problem :)
You can also take a look at my code, handling this event

How to find out if the message author is an element of my mongo database

EDIT: THIS IS FIXED!
I apparently forgot to reroute my mongoose connection to my Atlas!
I'm making a premium feature in my bot, that allows users to play music. Only thing wrong is that I can't find out how to find the message author's id in the database!
.findOne() returns promise that will resolve to the document if it's found, otherwise null. This means you can simply check if it's not null, you don't need to check if the IDs are the same. That's already checked by Mongoose.
Don't forget that you need to await the results if you're using promises.
try {
const premiumMember = await premiumSchema
.findOne({ userID: message.author.id })
.exec();
if (!premiumMember) {
return message.reply('You are not a premium user!');
}
const VC = message.member.voice.channel;
if (!VC)
return message.reply(
'You are not in a VC! Please join one and redo the command!',
);
const connection = await VC.join();
const dispatcher = connection
.play(ytdl(args[0]))
.on('finish', () => {
VC.leave();
message.channel.send(`${message.author}, your song has ended!`);
})
.on('error', (error) => {
console.log(error);
message.channel.send('There was an error playing this song');
});
dispatcher.setVolumeLogarithmic(5 / 5);
} catch (err) {
console.log(err);
}
use await before query like this:
const id = await premiumSchema.findOne({
userID: message.author.id
})
after that implement the business logic with == if you want to check the type ===
if(id.userID == message.author.id) {
return message.reply('You are not a premium user!')
}

Categories