Mongoose NextJS OverwriteModelError: Cannot overwrite `Note` model once compiled - reactjs

I am learning to use Mongoose with NextJS and I keep running into this error. I have looked over similar questions but didn't figure out how to solve this. I have followed a tutorial video for implementing Mongoose step by step but in the video this problem didn't occur. Also, I hate to say it this inaccurately but it only happens "sometimes". Seems like every time I run the server first POST request always goes through, GET requests are also fine but when I try multiple POST requests it occurs. After restarting the server it works again. Here is my code:
import mongoose from "mongoose"
const connection = {}
async function dbConnect() {
if (connection.isConnected) {
retrun
}
const db = await mongoose.connect(process.env.MONGO_URI, {
useNewUrlParser: true,
useUnifiedTopology: true,
})
connection.isConnected = db.connections[0].readyState
console.log(connection.isConnected)
}
export default dbConnect
const mongoose = require("mongoose")
let NoteSchema = new mongoose.Schema({
email: {
type: String,
required: [true, "Please enter your email"]
}
})
module.exports = mongoose.model.Note || mongoose.model("Note", NoteSchema);
import dbConnect from "../../utils/dbConnect"
import Note from "../../models/Note"
dbConnect()
export default async (req, res) => {
const { method } = req
switch(method) {
case "GET":
try {
const notes = await Note.find({})
res.status(200).json({ success: true, data: notes })
} catch (error) {
res.status(400).json({ success: false })
}
break
case "POST":
try {
const note = await Note.create(req.body)
res.status(201).json({ success: true, data: note })
} catch (error) {
res.status(400).json({ success:false })
}
break
default:
res.status(400).json({ success:false })
break
}
}
Thanks for any help.

you should use mongoose.models.Note instead of mongoose.model.Note
so just try:
module.exports = mongoose.models.Note || mongoose.model("Note", NoteSchema);
This method is used to prevent overwrite model once compiled Mongoose

Related

How to perform action or render component before/after every http request in React?

I want to know if there is a way to create a kind of middleware in React?
What i want is to have an alert component show if there is a failing result for an http request.
Right now, i am making http request on login,registration,etc and i am importing my alert component in every page and setting the Alert component props like type, message, visibility everywhere i need the component, but i think maybe there is a better way of doing this.
Here is my code:
...imports
export const RegisterPage = () => {
const [alertConfig, setAlertConfig] = useState({
type: "",
message: "",
show: false,
});
...code
const onSubmitHandler = async (e) => {
e.preventDefault();
if (!isFormValid()) return;
const formData = new FormData();
formData.append("password", formValues.password);
if (formValues.provider.startsWith("8")) {
formData.append("contact", formValues.provider);
} else {
formData.append("email", formValues.provider);
}
setIsLoading(true);
try {
const response = await fetch(
`${process.env.REACT_APP_API_URL}/auth/register`,
{
method: "POST",
body: formData,
}
);
const data = await response.json();
if (data.status === "success") {
const { token, user } = data.data;
dispatch(setCurrentUser(user, token));
navigate("/choose-actor");
} else {
setAlertConfig({
type: "warning",
message: data.message,
show: true,
});
}
} catch (error) {
console.log(error);
setAlertConfig({
type: "danger",
message: "Ocorreu algum erro",
show: true,
});
} finally {
setIsLoading(false);
}
};
return
...html
{alertConfig.show && <Alert {...alertConfig} />}
...more html
As you can see, i am changing the configuration for the alert inside inside the function that executes the http request, and i have to do the save for every page that performs this action.
I looking for a design patter where i dont have to repeat myself.
Hope my question is clear.

How to delete/remove from mongo database after a certain time of creating?

I'am having trouble figuring out how to delete a document from mongo DB after a timeout. Anyone can help me out with a simple way of doing it and maybe explain to me why this one is wrong? (it works, the document is deleted after some time , but I get a error message and the server stops)
this is the code I used written and also as a picture together with the terminal errormessage, I note, the document is deleted after the setTimeout runs out, but server stops:
documents are pretty simple consist of these:
server.js
import express from "express";
import cors from "cors";
import mongoose from "mongoose";
import shareRoutes from "./routes/shares.js";
const app = express();
app.use(cors());
app.get("/", (req, res) => {
res.json({ message: "API running..." });
res.end("");
});
app.use(express.json());
app.use("/radar", shareRoutes);
mongoose
.connect(
"mongodb+srv://<creditentials>#cluster0.dqlf2.mongodb.net/locations?retryWrites=true&w=majority",
{ useNewUrlParser: true },
{ useFindAndModify: false }
)
.then(() => {
app.listen(5000, () => {
"Server Running on port 5000";
});
})
.catch((err) => {
console.log(err);
});
shares.js for the route
import express from "express";
import {
createLocation,
getLocations,
} from "../controllers/shareController.js";
const router = express.Router();
// create location
router.post("/", createLocation);
// get Locations
router.get("/", getLocations);
export default router;
shareController.js
import express from "express";
import shareLocation from "../models/shareLocation.js";
const router = express.Router();
export const createLocation = async (req, res) => {
const { latitude, longitude, dateShared, timeShared, city, road } = req.body;
const newLocation = shareLocation({
latitude,
longitude,
dateShared,
timeShared,
city,
road,
});
try {
await newLocation.save();
res.status(201).json(newLocation);
setTimeout(() => {
(async () => {
try {
await shareLocation.findByIdAndRemove(newLocation._id);
res.json({ message: "Shared location deleted" });
} catch (error) {
res.status(409).json({ message: error });
}
})();
}, 30000);
} catch (error) {
res.status(409).json({ message: newLocation });
}
};
export const getLocations = async (req, res) => {
try {
const locations = await shareLocation.find({});
res.status(200).json(locations);
} catch (error) {
console.log(error);
res.status(409).json("Unable to fetch Locations");
}
};
export const deleteLocation = async (req, res) => {
const { id } = req.params;
try {
await shareLocation.findByIdAndRemove(id);
res.json({ message: "Shared location deleted" });
} catch (error) {
res.status(409).json({ message: error });
}
};
export default router;
shareLocations.js for the schema
import mongoose from "mongoose";
const hours = new Date().getHours().toLocaleString();
const minutes = new Date().getMinutes().toLocaleString();
const actualHours = hours.length < 2 ? "0" + hours : hours;
const actualMinutes = minutes.length < 2 ? "0" + minutes : minutes;
const locationSchema = mongoose.Schema({
timeShared: {
type: String,
default: actualHours + ":" + actualMinutes,
},
dateShared: {
type: String,
default: new Date().toDateString(),
},
latitude: {
type: String,
required: true,
},
longitude: {
type: String,
required: true,
},
city: {
type: String,
},
road: {
type: String,
},
});
export default mongoose.model("shareLocation", locationSchema);
I'll start with what is the "proper" solution, we'll take a look at what's wrong with the code after.
Mongo provides a built in way to remove documents after a certain time period, the "proper" way is to built a TTL index on the required field, and to specify after how many seconds you want that document deleted.
Mongo will then periodically check the index and clear documents when the time is up, this removes all kinds of levels of complexity from your app ( for example this timeout can easily cause a memory leak if too many calls are called in a short time window ).
A TTL index is created by using the simple createIndex syntax:
db.collection.createIndex( { "created_at": 1 }, { expireAfterSeconds: 30 } )
This will make documents expire 30 seconds after creation, you'll just have to add this timestamp to your code:
const newLocation = shareLocation({
latitude,
longitude,
dateShared,
timeShared,
city,
road,
created_at: new Date() // this new line is required
});
I can also tell you're using mongoose, then mongoose provides created_at field automatically if you set the Schema to include timestamps meaning your app can even ignore that.
Now what's wrong with your code?
It's simple, you first respond to the response in this line:
res.status(201).json(newLocation);
But then after a 30 second timeout you try to respond again, to the same response:
res.json({ message: "Shared location deleted" });
Node does not allow this behavior, you can only call set headers once ( which is called when responding ), I will not go into detail why as there are many stackoverflow answers (like this) that explain it.
Apart from the obvious issue that crashes your app, other issue's can arise from this code, as I mentioned before a memory leak can easily crash your app,
If your app restarts for whatever reason the locations that were "pending" in memory will not be cleared from the db, and more.
This is why it's recommended to let the DB handle the deletion.

Mongoose/Mongodb getting .deleteOne is not a function

When I click to delete a post, my console is saying TypeError: post.user.posts.deleteOne is not a function. It giving me this error after deleting.
const post = await Post.findByIdAndDelete(id).populate('user'); This code I am deleting the post from Post Schema
await post.user.posts.deleteOne(post)This code is to delete the post from the User Schema. I populated user and assigned it to post and then delete the user's post from this code, but I'm getting the error here.
Below is the controller code
export const deletePost = async (req, res) => {
const { id } = req.params;
try {
const post = await Post.findByIdAndDelete(id).populate('user');
await post.user.posts.deleteOne(post)
if (!post) {
return res.status(500).json({ message: "Unable To Delete" })
}
res.status(200).json({ message: "Deleted Successfully" })
} catch (error) {
console.log(error);
}
}
Client side delete request
const handleDeleteTrue = async () => {
try {
const { data } = await api.delete(`/post/${id}`)
console.log(data)
window.location.reload();
} catch (error) {
console.log(error.response.data.message);
}
};
User model schema
import mongoose from 'mongoose';
const userSchema = new mongoose.Schema({
name: {
type: String,
required: true
},
username: {
type: String,
required: true,
unique: true
},
email: {
type: String,
required: true,
unqie: true
},
password: {
type: String,
required: true,
minlength: 6
},
posts: [{ type: mongoose.Types.ObjectId, ref: "Post", required: true }]
});
export default mongoose.model('User', userSchema);
Im able to delete the post from the post model schema, but in this pic, which shows the user model schema, that same post that was deleted is not deleted here. This is the problem Im trying to solve.
What I can seem to understand in your function below is that you're trying to delete a single post and also checking if post exists first
export const deletePost = async (req, res) => {
const { id } = req.params;
try {
const post = await Post.findByIdAndDelete(id).populate('user');
await post.user.posts.deleteOne(post)
if (!post) {
return res.status(500).json({ message: "Unable To Delete" })
}
res.status(200).json({ message: "Deleted Successfully" })
catch (error) {
console.log(error);
}
}
I'd suggest you try this
export const deletePost = async (req, res) => {
const { id } = req.params;
try {
//check if document exists in mongoDB collection
if (!mongoose.Types.ObjectId.isValid(id)) {
return res.status(500).json({ message: "Unable To Delete" }) }
await Post.deleteOne(id)
res.status(200).json({ message: "Deleted Successfully" })
catch (error) {
console.log(error);
}
}
I found out the answer. My user model schema for post was an array so I had to use $pull to delete it.
This is the code that worked for me
await post.user.posts.pull(post)
await post.user.save()
You can't use findOneAndDelete on populate to delete one object from an array. it doesn't work that way. Use This Instead.
const result = await User.findOneAndUpdate(
{ _id: Id },
{ $pull: { post:PostId } },
{ new: true }
);
You can find More on Pull and Push Operations on BlogLink

I'm trying to replicate the devconnector project but when I make post request a profile route create profile the post request is pending

this is the route:
router.post(
'/',
[ auth,
check('status', 'Status is required').not().isEmpty(),
check('skills', 'Skills is required').not().isEmpty(),
],
async (req, res) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}
// destructure the request
const {
website,
skills,
youtube,
twitter,
instagram,
linkedin,
facebook,
// spread the rest of the fields we don't need to check
...rest
} = req.body;
// build a profile
const profileFields = {
user: req.user.id,
website:
website && website !== ''
? normalize(website, { forceHttps: true })
: '',
skills: Array.isArray(skills)
? skills
: skills.split(',').map((skill) => ' ' + skill.trim()),
...rest
};
// Build socialFields object
const socialFields = { youtube, twitter, instagram, linkedin, facebook };
// normalize social fields to ensure valid url
for (const [key, value] of Object.entries(socialFields)) {
if (value && value.length > 0)
socialFields[key] = normalize(value, { forceHttps: true });
}
// add to profileFields
profileFields.social = socialFields;
try {
// Using upsert option (creates new doc if no match is found):
let profile = await Profile.findOneAndUpdate(
{ user: req.user.id },
{ $set: profileFields },
{ new: true, upsert: true, setDefaultsOnInsert: true }
);
return res.json(profile);
} catch (err) {
console.error(err.message);
return res.status(500).send('Server Error');
}
}
);
this is Axios:
axios.post('/api/profile',profileData, {headers:{
'x-auth-token': localStorage.getItem('jwtToken')
}}).then(data => console.log(data)).catch(e => console.error(e))
this is problem:
pending
Have you tried to use debugger in order to follow software flow?
Have you any log from express side?
I'd start checking if let profile = await Profile.findOneAndUpdate is reached in order to define if the problem starts on db request.
At this stage I would say that the execution is pending waiting for db timeout

Why am I getting a 405 error in production but not development?

This is the first project I've built from scratch and first time deploying anything with AWS, ubuntu, nginx. The app is built with postgres, express/node, and react.
When I click the login button in production, I get this error: POST http://18.216.221.221/dashboard/api/1/login 405 (Not Allowed)
But in development the POST request works fine and goes to http://localhost:5000/api/1/login
I can't figure out why in production it's adding the "dashboard" to the URL.
This is the server route:
app.post('/api/1/login', async (req, res)=>{
if (!req.body.username || !req.body.password) {
return res.status(400).json('missing fields')
}
try {
const result = await db.query("select * from login where username = $1", [req.body.username])
const isValid = bcrypt.compareSync(req.body.password, result.rows[0].hash);
if (isValid) {
res.status(200).json({
status: 'login successful',
data: {
user: result.rows[0].username
}
})
} else {
res.status(400).json({
status: 'login failed'
})
}
} catch(error) {
console.log('unable to login')
}
})
And this is the function for handling the login:
const handleLogin = async (e) => {
e.preventDefault()
try {
const response = await ClientFilesApi.post(`/login`, {
username,
password
})
console.log(response)
if (response.data.data.user === 'myemail') {
setUserLoggedIn(true)
setPassword("")
history.push(`/dashboard`)
}
} catch (err) {
console.log(err)
}
}
I've set my api baseURL like this:
const baseURL = process.env.NODE_ENV === 'production' ? "api/1" : "http://localhost:5000/api/1"
export default axios.create({
baseURL
})
I've followed all the instructions for deploying from this tutorial:
https://github.com/Sanjeev-Thiyagarajan/PERN-STACK-DEPLOYMENT
And this is my source code:
https://github.com/cipdv/ciprmt

Resources