findOneAndUpdate is not a function of mongoose - javascript

I know this question has been answered before but I can't seem to implement the changes into what im working with. I'm trying to create a daily command that rewards a user for doing s!daily. I get the error,
TypeError: profileData.findOneAndUpdate is not a function
at Object.execute (C:\Users--\Desktop\DiscBot\commands\daily.js:35:43)
at module.exports (C:\Users--\Desktop\DiscBot\events\client\message.js:34:13)
daily.js, one having error at line 35 for findOneAndUpdate is not a function
const Schema = require('../models/profileSchema')
//cache users that claim daily rewards
let claimedCache = []
const clearCache = () => {
claimedCache = []
setTimeout(clearCache, 1000 * 60 * 10)
}
clearCache()
//message to make it easier later
const alreadyClaimed = 'You have already claimed your daily rewards'
module.exports = {
name: "daily",
aliases: ["day", "d"],
permissions: [],
description: "Claim your daily rewards!",
async execute(message, args, cmd, client, Discord, profileData) {
const { serverID, member } = message
const { id } = member
//If user is in cache return message
if (claimedCache.includes(id)) {
console.log('Returning from cache')
message.reply(alreadyClaimed)
return
}
//Put everything in object for later
const obj = {
guildId: serverID,
userId: id,
}
//Results is an update that either updates if is user is not in array and doesn't if they are, but it doesn't know what findOneAndUpdate is (thought it was just a mongo/mongoose function??)
try {
const results = await profileData.findOneAndUpdate(obj)
console.log('RESULTS:', results)
if (results) {
const then = new Date(results.updatedAt).getTime()
const now = new Date().getTime()
const diffTime = Math.abs(now - then)
const diffDays = Math.round(diffTime / (1000 * 60 * 60 * 24))
if (diffDays <= 1) {
claimedCache.push(id)
message.reply(alreadyClaimed)
return
}
}
//after the update increase coins by 50 and send claimed message
await profileRewardsSchema.findOneAndUpdate(obj, obj, {
upsert: true,
})
claimedCache.push(id)
const amount = 50;
await profileModel.findOneAndUpdate(
{
userID: id,
},
{
$inc: {
coins: amount,
},
}
);
message.reply('You have claimed your daily rewards!')
}catch (err) {
console.log(err);
}
}
}
message.js, heres where I make profileModel a thing using mongoose to pass it into my commands
const profileModel = require("../../models/profileSchema");
const config = require('../../config.json');
module.exports = async (Discord, client, message) => {
//command handler start
const prefix = 's!';
if (!message.content.startsWith(prefix) || message.author.bot) return;
//database junk
let profileData;
try {
profileData = await profileModel.findOne({ userID: message.author.id });
if (!profileData) {
let profile = await profileModel.create({
userID: message.author.id,
serverID: message.guild.id,
coins: 10,
bank: 0,
});
profile.save();
}
} catch (err) {
console.log("Error creating new database profile");
}
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) return message.channel.send(":x: This is not a valid command");
try {
command.execute(message, args, cmd, client, Discord, profileData);
} catch (err) {
message.reply('There was an error executing that command!');
}
};
profileSchema.js, Where profile is made into mongo database
const mongoose = require("mongoose");
const profileSchema = new mongoose.Schema({
userID: { type: String, require: true, unique: true },
serverID: { type: String, require: true },
coins: { type: Number, default: 10 },
bank: { type: Number },
},
{
timestamps: true,
}
)
const model = mongoose.model("ProfileModels", profileSchema);
module.exports = model;
main.js, where mongoose is connected, then passed on
mongoose.connect(process.env.MONGODB_SRV, {
useNewUrlParser: true,
useUnifiedTopology: true,
useFindAndModify: false
})

You are trying to call findOneAndUpdate on the document, which you passed to execute function at message.js. Check the example of how to use findOneAndUpdate
https://mongoosejs.com/docs/tutorials/findoneandupdate.html

Most of the time this error happen when you call findOneAndUpdate in mongoose when you call it on the instance of the model NOT the actual model
so instead of this
var NewUser = new User(req.user);
NewUser.findOneAndUpdate...
do this
var NewUser = new User(req.user);
User.findOneAndUpdate(
{ name: NewUser.name },
{ name: NewUser.name},
{ upsert: true });

Related

MongoDB only using one entry - Discord.js

Currently I have a command of which checks someone else's balance with my sort of economy system. The issue is that it's only storing one users data - so when the database is empty and the bot goes to create a profile for a user that is the only profile ever created - for example when another member goes to check their balance then it won't show their own profile but it shows only the first person to create a profile's balance. I've tried everything - nothing works. Please help... Below is the command to check balance, my schema and the profile creating function.
if (message.author.bot) return;
let member = message.mentions.members.first();
if (member) {
if (message.content.match('!ponyo balance') && profileSchema.findOne({ memberId: member.id, guildId: member.guild.id })) {
console.log('trying to execute balance.createBalance() with the user id: ' + member.id)
const profileBalance = await balance.createBalance(member);
console.log(`profileBalance: ${profileBalance}`)
await message.reply(`${message.mentions.members.first()} has ${profileBalance.coins} coins! :D`);
}
}
})
const Balance = require('./profileSchema')
const mongoose = require('mongoose')
//create profile thingy
async function createBalance(member) {
if (Balance.findOne({ memberId: member.id })) {
let balanceProfile = await Balance.findOne({ memberId: member.id })
if (balanceProfile) {
return balanceProfile;
} else {
balanceProfile = await new Balance({
userID: member.id,
serverID: member.guild.id
});
await balanceProfile.save().catch(err => console.log(err));
console.log("returning: " + balanceProfile.toString());
return balanceProfile;
}}}
module.exports = { createBalance };
const mongoose = require('mongoose');
const profileSchema = new mongoose.Schema({
userID: { type: String, require: true, unique: true},
serverID: { type: String, require: true },
coins: { type: Number, default: 100 },
bank: { type: Number }
})
const model = mongoose.model('ProfileModels', profileSchema);
module.exports = model;
There is no memberId in your profile Schema..
if (Balance.findOne({ memberId: member.id })) {
Maybe you are mistakenly put memberId instead of userId or
you have Separate Balance Scheme.. which is not imported Correctly..

Why could the findOrCreate plugin create several documents at once?

I'm currently working on a MERN application with following/follower function for the users. I decided to create separate schemas for following and follower relationships detached from user schema.
Follower schema
const mongoose = require('mongoose');
const findOrCreate = require('mongoose-findorcreate');
const ObjectId = mongoose.Schema.Types.ObjectId;
const followerSchema = mongoose.Schema({
userId: {
type: ObjectId,
ref: 'User'
},
follower: {
type: [ObjectId],
ref: 'User'
}
});
followerSchema.plugin(findOrCreate);
const Follower = mongoose.model('Follower', followerSchema);
module.exports = { followerSchema, Follower };
Following schema
const mongoose = require('mongoose');
const findOrCreate = require('mongoose-findorcreate');
const ObjectId = mongoose.Schema.Types.ObjectId;
const followingSchema = mongoose.Schema({
userId: {
type: ObjectId,
ref: 'User'
},
following: {
type: [ObjectId],
ref: 'User'
}
});
followingSchema.plugin(findOrCreate);
const Following = mongoose.model('Following', followingSchema);
module.exports = { followingSchema, Following };
The problem however starts in my service where followings are created as supposed to. However, for followers mongoose create 6-8 documents at once with userIds that don't even exist in my db.
Here's the code of the followerService (it's the first function)
const { Follower } = require('../models/followerModel');
const { Following } = require('../models/followingModel');
const { User } = require('../models/userModel');
const mongoose = require('mongoose');
exports.changeFollowStatus = async (user, userId) => {
console.log({ userId: userId, user: user._id });
const newFollowing = await Following.findOrCreate({ userId: user._id }, (err, following, created) => {
console.log({following: following});
if (!err && !isFollowing(following, userId)) {
following.following.push(mongoose.Types.ObjectId(userId));
following.save();
User.findByIdAndUpdate(mongoose.Types.ObjectId(userId), {$inc: {follower: 1}});
} else {
const followingIndex = following.following.indexOf(mongoose.Types.ObjectId(userId));
following.following.splice(followingIndex, 1);
following.save();
User.findByIdAndUpdate(mongoose.Types.ObjectId(userId), { $inc: { follower: -1 } });
}
});
const newFollower = await Follower.findOrCreate({ userId: mongoose.Types.ObjectId(userId) }, (err, follower, created) => {
console.log({follower: follower});
if (!err && !isFollower(follower, user._id)) {
follower.follower.push(user._id);
follower.save();
User.findByIdAndUpdate(user._id, { $inc: { following: 1 } });
} else {
const followerIndex = follower.follower.indexOf(user._id);
follower.follower.splice(followerIndex, 1);
follower.save();
User.findByIdAndUpdate(user._id, { $inc: { following: -1 } });
}
});
};
exports.showFollowings = async (userId) => {
const followings = await Following.findOrCreate({ userId: mongoose.Types.ObjectId(userId) });
return followings.following;
};
exports.showFollowers = async (userId) => {
const followers = await Follower.findOrCreate({ userId: mongoose.Types.ObjectId(userId) });
return followers.follower;
};
const isFollowing = (newFollowing, userId) => {
return newFollowing.following.includes(mongoose.Types.ObjectId(userId));
};
const isFollower = (newFollower, userId) => {
return newFollower.follower.includes(userId);
}
Now, my following adding code and follower adding code look almost identical, but for some reason for followers, mongoose creates many more documents. The strange thing is that there is a follower document with the correct userId, but many other with random userIds get created which doesn't happen with followings which works as supposed to.
I also checked whether I pass the correct values and everything seems to be fine. But just for reference, here's the controller function from which I pass the values.
exports.changeFollowingStatus = async (req, res, next) => {
passport.authenticate('jwt', async (err, user, info) => {
if (err) {
console.error({ authError: err });
};
if (info !== undefined) {
console.error({ authError: info.message });
res.status(403).send(info.message);
} else {
console.log({params: req.params});
const userToFollow = req.params.id;
await FollowerService.changeFollowStatus(user, userToFollow);
res.status(200).send({ message: 'success' })
}
})(req, res, next);
};
Could anyone help me with this bug or at least navigate me towards the right direction? I can't seem to find solution to my problem. Thank you all in advance!

Collecting the first one to respond's userID

I recently made this command where users have 15 seconds to type 'catch' to win coins. The only issue is that I'm not sure how to make it so that the coins go to the person who typed 'catch' first. Right now it's set up so that the coins always goes to the person who triggered the command. I tried using the discord.js guide for collectors but I kept getting errors. I'm still pretty new at this, anything helps thanks.
const profileModel = require("../models/profileSchema");
module.exports = {
name: "catch",
description: "users must type catch first to catch the animal",
async execute(client, message, msg, args, cmd, Discord, profileData) {
const prey = [
"rabbit",
"rat",
"bird",
];
const caught = [
"catch",
];
const chosenPrey = prey.sort(() => Math.random() - Math.random()).slice(0, 1);
const whenCaught = caught.sort(() => Math.random() - Math.random()).slice(0, 1);
const earnings = Math.floor(Math.random() * (20 - 5 + 1)) + 5;
const filter = ({ content }) => whenCaught.some((caught) => caught.toLowerCase() == content.toLowerCase());
const collector = message.channel.createMessageCollector({ max: 1, filter, time: 15000 });
collector.on('collect', async (m) => {
if(m.content?.toLowerCase() === 'catch') {
message.channel.send(`You caught the ${chosenPrey}! You gained ${earnings} coins.`);
}
await profileModel.findOneAndUpdate(
{
userID: message.author.id,
},
{
$inc: {
coins: earnings,
},
}
);
});
collector.on('end', (collected, reason) => {
if (reason == "time") {
message.channel.send('Too slow');
}
});
message.channel.send(`Look out, a ${chosenPrey}! Type CATCH before it gets away!`);
}
}
The profileSchema just in case
const profileModel = require("../../models/profileSchema");
const cooldowns = new Map();
module.exports = async (Discord, client, message) => {
let profileData;
try {
profileData = await profileModel.findOne({ userID: message.author.id });
if(!profileData){
let profile = await profileModel.create({
name: message.member.user.tag,
userID: message.author.id,
serverID: message.guild.id,
coins: 0,
});
profile.save();
}
} catch (err) {
console.log(err);
}
It looks like your collector is using two different variables for message:
collector.on('collect', async (m) => {
if(m.content?.toLowerCase() === 'catch') {
message.channel.send(`You caught the ${chosenPrey}! You gained ${earnings} coins.`);
}
await profileModel.findOneAndUpdate(
{
userID: message.author.id,
},
{
$inc: {
coins: earnings,
},
}
);
});
You're checking whether the message m (collected by your collector) has the content 'catch', and then finding the userID of the user that checking the author of the message (from your execute() parameters up top, so, the message that triggered this command) when you should be using m.
So, to fix this, you should change userID: message.author.id to userID: m.author.id

DiscordAPIError: Invalid Form Body 3.options[1].type: This field is required

so I have this lockdown command I just made, but when I want to start the bot I get the following error
DiscordAPIError: Invalid Form Body
3.options[1].type: This field is required
I tried fixing it but I have no idea where the issue is.
It exists of 4 files.
File 1: GiveawaySys.js <-- system file
const { GiveawaysManager } = require('discord-giveaways');
const giveawayModel = require("../Structures/Schemas/GiveawayDB");
module.exports = (client) => {
const GiveawayManagerWithOwnDatabase = class extends GiveawaysManager {
async getAllGiveaways() {
return await giveawayModel.find().lean().exec();
}
async saveGiveaway(messageId, giveawayData) {
await giveawayModel.create(giveawayData);
return true;
}
async editGiveaway(messageId, giveawayData) {
await giveawayModel.updateOne({ messageId }, giveawayData, { omitUndefined: true }).exec();
return true;
}
async deleteGiveaway(messageId) {
await giveawayModel.deleteOne({ messageId }).exec();
return true;
}
};
const manager = new GiveawayManagerWithOwnDatabase(client, {
default: {
botsCanWin: false,
embedColor: '#FF0000',
embedColorEnd: '#000000',
reaction: '🎉'
}
});
client.giveawaysManager = manager;
}
File 2: Lockdown.js <-- Schema
const { model, Schema } = require("mongoose");
module.exports = model("Lockdown", new Schema({
GuildID: String,
ChannelID: String,
Time: String,
})
);
File 3: lock.js <-- lock command
const {
CommandInteraction,
MessageEmbed
} = require("discord.js");
const DB = require("../../Structures/Schemas/LockDown");
const ms = require("ms");
module.exports = {
name: "lock",
description: "Lockdown this channel",
permission: "MANAGE_CHANNELS",
options: [{
name: "time",
description: "Expire date for this lockdown (1m, 1h, 1d)",
type: "STRING",
},
{
name: "reason",
description: "Provide a reason for this lockdown.",
tyoe: "STRING",
},
],
/**
*
* #param {CommandInteraction} interaction
*/
async execute(interaction) {
const {
guild,
channel,
options
} = interaction;
const Reason = options.getString("reason") || "no specified reason";
const Embed = new MessageEmbed();
if (!channel.permissionsFor(guild.id).has("SEND_MESSAGES"))
return interaction.reply({
embeds: [Embed.setColor("RED").
setDescription("â›” | This channel is already locked."),
],
ephemeral: true,
});
channel.permissionOverwrites.edit(guild.id, {
SEND_MESSAGES: false,
});
interaction.reply({
embeds: [Embed
.setColor("RED")
.setDescription(`🔒 | This channel is now under lockdown for: ${Reason}`
),
],
});
const Time = options.getString("time");
if (Time) {
const ExpireDate = Date.now() + ms(Time);
DB.create({
GuildID: guild.id,
ChannelID: channel.id,
Time: ExpireDate
});
setTimeout(async () => {
channel.permissionOverwrites.edit(guild.id, {
SEND_MESSAGES: null,
});
interaction.editReply({
embeds: [Embed
.setDescription("🔓 | The lockdown has been lifted")
.setColor("GREEN")
],
})
.catch(() => {});
await DB.deleteOne({
ChannelID: channel.id
});
}, ms(Time));
}
},
};
File 4: unlock.js <-- unlock command
const {
CommandInteraction,
MessageEmbed
} = require("discord.js");
const DB = require("../../Structures/Schemas/LockDown");
module.exports = {
name: "unlock",
description: "Lift a lockdown from a channel",
permission: "MANAGE_CHANNELS",
/**
*
* #param {CommandInteraction} interaction
*/
async execute(interaction) {
const {
guild,
channel
} = interaction;
const Embed = new MessageEmbed();
if (channel.permissionsFor(guild.id).has("SEND_MESSAGES"))
return interaction.reply({
embeds: [Embed
.setColor("RED")
.setDescription("â›” | This channel is not locked"),
],
ephemeral: true,
});
channel.permissionOverwrites.edit(guild.id, {
SEND_MESSAGES: null,
});
await DB.deleteOne({
ChannelID: channel.id
});
interaction.reply({
embeds: [Embed
.setColor("GREEN")
.setDescription("🔓 | Lockdown has been lifted."),
],
});
},
};
Please help me with this one, I can't find the issue here
The error you are getting (.options[1].type is required) is a very big hint as to what the issue is. Searching the code of your files, I saw this in your third file in options[1]:
{
name: "reason",
description: "Provide a reason for this lockdown.",
tyoe: "STRING",
}
Notice the problem? It's a typo. "tyoe" instead of "type", causing djs to complain about "type" being required.

Mongoose Only Updating Once?

So I'm making a setnote command so people can keep track of how much they have donated. However, It will only add it when I add them to the database and not after. I don't know why. So it just isn't updating or sending the message that it's even updated.
const { MessageEmbed } = require('discord.js')
const notesModel = require('../models/notesSchema')
module.exports = {
name: 'setnote',
aliases: ['sn'],
description: 'Add a note to a user.',
async execute(message, args, client, cmd, Discord, notesData) {
const mentionedMember = message.mentions.members.first() || message.guild.members.cache.get(args[0])
if (!args[0]) return message.channel.send('Please mention someone to add note to.')
if (!args[1]) return message.channel.send('Please state an amount to add to the user.')
const amountToAdd = args[1]
if (isNaN(args[1])) return message.channel.send('You have to add a number when setting note.')
let userData = await notesModel.findOne({
userID: mentionedMember.id,
serverID: message.guild.id,
})
if (!userData) {
userData = await notesModel.create({
userID: mentionedMember.id,
serverID: message.guild.id,
notes: 0
})
const response = await notesModel.findOneAndUpdate({
serverID: message.guild.id,
userID: mentionedMember.id
}, {
$inc: {
notes: +amountToAdd
}
})
userData = await notesModel.findOne({serverID: mentionedMember.guild.id, userID: mentionedMember.id});
function numberWithCommas(x) {
return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',');
}
const addedNote = new MessageEmbed()
.setTitle(`<a:red_check:845104782833352704> Successfully Added Note <a:red_check:845104782833352704>`)
.setDescription(`${mentionedMember.user.tag} has now donated \`${numberWithCommas(userData.notes)}\``)
.setColor('GREEN')
message.channel.send(addedNote)
}
}
}

Categories

Resources