I'm currently working on the backend of a shopping website,
while working on my post functions. I get this error
"OverwriteModelError: Cannot overwrite User model once compiled."
Everything works fine until when i go for the buy character where it needs a search query for both the User and Character and pushing the character into the array ownedCharacter in the User model.
when i remove the const User = require('../Model/User'); and test the function buy character in postman it says that the User is Undefined.
Here's the code for the model
const mongoose = require('mongoose');
const UserSchema = new mongoose.Schema({
username:{
type: String,
required : true
},
email:{
type: String,
required: true
},
password:{
type: String,
required: true,
min: 8
},
status:{
type:Boolean,
default:false
},
points:{
type:Number,
default: 0
},
rank:{
type:String,
default:"unranked"
},
avatar:{
type:String,
default:""
},
level:{
type:Number,
default:0
},
experience:{
type:Number,
default:0
},
registrationDate:{
type:Date,
default:Date.now()
},
gold:{
type:Number,
default:0
},
gems:{
type:Number,
default:0
},
ownedCharacter:[{
type:mongoose.Schema.Types.ObjectId,
ref:"Character",
}],
},{timestamps:true});
module.exports = mongoose.model("User", UserSchema);
Here's the code for the app.js
const express = require('express');
const app = express();
const mongoose = require('mongoose');
const dotenv = require('dotenv');
const bodyParser = require("body-parser");
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
extended: true
}));
app.use(express.static('uploads'));
//Import Routes
const authRoute = require ('./Route/Auth');
const authAdminRoute = require ('./Route/Admin_Auth');
const shopRoute = require('./Route/Shop');
dotenv.config();
//Connection to DataBase
mongoose.connect(
process.env.DB_CONNECT,
{useNewUrlParser: true, useUnifiedTopology: true},
()=>console.log('connected to database')
);
//MiddleWares
app.use(express.json());
//Route MiddleWares
app.use('/api/user', authRoute);
app.use('/api/admin', authAdminRoute);
app.use('/api/shop',shopRoute);
//Server Listener
app.listen(27017, ()=> console.log("Server Running"));
and here's the shop route
const router = require('express').Router();
const User = require('../Model/User');
const Character = require('../Model/Character');
const Skin = require('../Model/Skin');
//admin add character
router.post('/addCharacter', async (req, res) =>{
const character = new Character({
name:req.body.name,
price:req.body.price,
story:req.body.story,
ability:{
abilityName:req.body.abilityName,
cooldown:req.body.cooldown,
description:req.body.description
},
});
try {
const savedCharacter = await character.save();
res.json({savedCharacter});
console.log(character);
} catch (error) {
}
});
//add Skin
router.post('/addSkin/:characterId', async (req, res) =>{
const skin = new Skin({
name:req.body.name,
price:req.body.price,
description:req.body.description,
characterId: req.params.characterId
});
try {
const savedSkin = await skin.save();
res.json({skin});
console.log(skin);
} catch (error) {
}
});
//add Monsters
router.post('/addMonster/', async (req, res) =>{
const mosnter = new Monster({
name:req.body.name,
price:req.body.price,
description:req.body.description,
});
try {
const savedMonster = await monster.save();
res.json({monster});
console.log(monster);
} catch (error) {
}
});
//add Traps
router.post('/addTrap', async (req, res) =>{
const trap = new Trap({
name:req.body.name,
price:req.body.price,
description:req.body.description,
});
try {
const savedTrap = await trap.save();
res.json({trap});
console.log(trap);
} catch (error) {
}
});
//buy a Character
router.post('/buyCharacter/:characterId/:userId',async(req,res)=>{
try {
const user = await User.findOne({_id:req.params.userId});
console.log("user:"+user);
const boughtCharacter = await Character.findOne({_id:req.params.characterId});
user.ownedCharacter.push(boughtCharacter);
user.save();
res.json(boughtCharacter);
console.log(boughtCharacter);
} catch (error) {
console.log(error.message);
}
});
module.exports = router;
Is the casing correctly matched between your require statements and the file names? If the filename is actually /Model/user.js, it could throw this error.
The error message is telling you that somehow, you are declaring a model named User more than once. Unless you are explicitly doing so again in another file, you're best bet is that the User.js file is being loaded twice. There are a few reasons why that can happen, but the most likely cause is that you are importing the ../Model/User.js file in multiple places, but your casing is inconsistent.
When Node loads an import, it caches it using the resolved filename you pass to require()... and it does so in a case-sensitive manner. What that means is that if you have require(../Model/user) in one file and require(../Model/User) in
another, Node will load the same file twice, thus executing the file twice, thus attempting to set a model named User on the shared mongoose instance twice, and thus giving you the OverwriteModelError you are experiencing.
I'd do a find in your IDE and look at everywhere you are requiring that model.
Related
here when I try to insert the data with proper validation it works. and when I post with wrong validation it also throws error as expected but when I use the email that was already present in my database and i had set the unique:true but it stores the document with same email.
What am i doing wrong
My model file:
const mongoose = require("mongoose")
const Userschema = new mongoose.Schema({
name:{
type:String,
required:true
},
email:{
type:String,
required:true,
unique:true,
},
password:{
type:String,
required:true
},
date:{
type:Date,
default:Date.now
}
})
const User = new mongoose.model("user", Userschema)
module.exports = User
main file:
const express = require("express");
const router = express.Router();
const User = require("../models/User");
const { body, validationResult } = require("express-validator");
router.post(
"/createuser",
[
body("name", "please enter valid name").isLength({ min: 5, max: 15 }),
body("password", "your password must be larger or equalt to 8 characters").isLength({ min: 8 }),
],
async (req, res) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}
try {
const data = await User.create(req.body);
res.json(data);
} catch (error) {
console.log(error);
res.send("some error occured")
}
}
);
The code is correct, If you add the unique after running the API to save the user in DB. It will not work. Because unique indexing runs the first time while creating collections. No worry, drop the data and run API. It should be working. If you don't want to drop the DB. The other solution is to write a migration task to create a unique index.
const { MongoClient } = require('mongodb');
const createIndex = async () => {
try {
const url = 'paste your db url';
const client = new MongoClient(url);
const dbName = 'paste your db name';
await client.connect();
const db = client.db(dbName);
await db.collection('users').createIndex(
{email: 1 },
{ unique: true },
);
process.exit(1);
} catch (err) {
console.log(err.stack);
}
};
createIndex();
Run the above code with 'node'.
I write node.js code and try to insert data into a mongodb database by Postman (post) but the data is not saved, only _id and _v are inserted into the documents ,that are entered automatically. I think the problem is in the body-parser, it is deprecated, but I tried a few options and it remained deprecated. (I'm not sure the problem with bodyparser).The data were inserteded via Postman(post). This is the relevant node.js code:
const express = require ('express');
const mongoose = require ('mongoose');
const router = require ('./routes/api');
const bodyParser = require("body-parser");
const dotenv = require('dotenv');
dotenv.config();
const app = express();
.
.
.
app.use(bodyParser.json());//this bodyParser is deprecated
app.use('/',router);
model:
const mongoose = require ('mongoose');
const userSchema = mongoose.Schema({
name:{
type:String,
require
},
password:{
type:String,
minlength:8,
require
}
})
module.exports = mongoose.model('User', userSchema);
controller:
const User = require ('../models/User');
const newUser = async (req,res)=>{
let user1 = new User(
req.body);
console.log(`${user1} added`);
try{
await user1.save();
res.status(200).json({newUser:user1});
}
catch(error){
res.send(`cant save new user: ${error.message}`)
}
}
module.exports = { newUser }
This is what I wrote in Postman:
{
"name":"james",
"password":"12345678"
}
and this is the response:
{
"newUser": {
"_id": "60a68f815019f31cfc098572",
"__v": 0
}
}
I would be very happy to get help !!
Please make the following changes to get the desired result.
// In place of app.use(bodyParser.json()), use
app.use(express.json())
// Controller
const userSchema = require("../models/User");
const newUser = async (req, res) => {
let user1 = new userSchema({
name: req.body.name,
password: req.body.password,
});
console.log(`${user1} added`);
try {
await user1.save().then(() => res.status(201).json({ newUser: user1 }));
} catch (error) {
res.send(`cant save new user: ${error.message}`);
}
};
module.exports = { newUser };
Also, inside the user schema, please change require to required: true.
// Model
const userSchema = new mongoose.Schema({
name:{
type: String,
required: true
},
password:{
type: String,
minLength:8,
required: true
}
})
Modify your model.js file. It will check if anything is missing in req.body
const mongoose = require ('mongoose');
const userSchema = mongoose.Schema({
name:{
type:String,
required: true
},
password:{
type:String,
minlength:8,
required: true
}
})
module.exports = mongoose.model('User', userSchema);
I created a small project with node+express+mongodb
This is where i call the create user:
const express = require("express");
const User = require("../models/user");
const router = express.Router();
router.post("/register", async (req, res) => {
try {
const user = await User.create(req.body);
return res.send({ user });
} catch (e) {
return res.status(400).send({ error: "Registration failed" });
}
});
module.exports = app => app.use("/auth", router);
and here is the Schema for the user:
const mongoose = require("mongoose");
const UserSchema = new mongoose.Schema({
name: {
type: String,
require: true
},
email: {
type: String,
require: true,
unique: true,
lowercase: true
},
password: {
type: String,
require: true,
select: false
},
createdAt: {
type: Date,
default: Date.now
}
});
const User = mongoose.model("User", UserSchema);
module.exports = User;
But when o make the resquest, it nevers get a response, it waits forever. And when o take out the await from the request, it gets an empty response { "user": {}}
I'm kind lost looking the mongoose documentation (the ideia is to make a simple rest api, i'm used with python, but looking to learn node)
You have to create a new user from User Model as follows:
const express = require("express");
const User = require("../models/user");
const router = express.Router();
router.post("/register", async (req, res) => {
try {
var user = new User(request.body);
var result = await user.create();
return res.send({ result });
} catch (e) {
return res.status(400).send({ error: "Registration failed" });
}
});
module.exports = app => app.use("/auth", router);
Client.js
const mongoose = require("mongoose");
var Schema = mongoose.Schema;
const clientSchema = new mongoose.Schema(
{
name: { type: String, required: true, default: "" },
}, {
timestamps: true
}
);
module.exports = mongoose.model("Client", clientSchema);
User.js
const mongoose = require("mongoose");
var Schema = mongoose.Schema;
const userSchema = new mongoose.Schema({
name: { type: String, required: true, default: "" },
clients: [{
client: {
type: Schema.Types.ObjectId,
ref: "Client",
default: null
},
user_group: {
type: Number
default: null
}
}]
}, { timestamps: true });
module.exports = mongoose.model("User", userSchema);
auth.js (Where trying to populate Clients)
const express = require("express");
const router = express.Router();
const User = require("../models/User");
const Client = require("../models/Client");
router.post("/users", (req, res) => {
let params = req.body;
let total_client = [];
User.findOne({
email: params.email
})
.populate({
path: "clients.client",
model: Client
})
.exec((err, user) => {
console.log(user);
res.send(user);
});
});
module.exports = router;
Please check the above code. I have given code examples of my two models user.js and client.js. In user schema, I have referenced client inside an array object. While querying user, the client is not population. Please help me to get this thing done. Thanks in advance.
The following expects you to provide a name in the json body of your post request (your example uses email which does not exist in the user model). Also, your model is already defining the ref: Client and so you can simplify your request to just include the path clients.client.
router.post("/users", async (req, res) => {
const { name } = req.body;
const user = await User.findOne({ name: name }).populate('clients.client').exec();
res.send(user);
});
Solved this problem just adding an extra parameter in module export of client.js file
module.exports = mongoose.model("Client", clientSchema, "client");
I'm learning the MERN stack and encountered an issue on the edit route of my child router.
I have the below model schemas in songs.js and students.js files:
const mongoose = require('mongoose');
const studentSchema = mongoose.Schema({
name: { type: String, required: true },
instrument: String,
songs: [{
type: mongoose.Schema.Types.ObjectId,
ref: 'Song'
}]
});
const Student = mongoose.model('Student', studentSchema);
module.exports = Student;
const mongoose = require('mongoose');
const songSchema = mongoose.Schema({
name: { type: String, required: true },
img: String
})
const Song = mongoose.model('Song', songSchema);
module.exports = Song
And I have songs.js and students.js files for my routers, with mergeParams set to true for my songs router const songs = express.Router({ mergeParams: true });. I'm attaching it to the students router like this:
students.use('/:id/songs', songs);
e.g., my url parameters become students/student1/songs/song1
All of my other routes are working, but on the update route of my songs router I'm getting an error "TypeError: Student.findById is not a function" when I redirect back to the song's index view. My edit and update routes
are below:
songs.get('/:songId/edit', async (req, res) => {
try {
const findSong = Song.findById(req.params.songId);
const findStudent = Student.findById = (req.params.id);
const [foundSong, foundStudent] = await Promise.all([findSong, findStudent]);
res.render('songs/edit', {
student: foundStudent,
song: foundSong
})
} catch (err) {
console.log(err);
}
});
songs.put('/:songId', async (req, res) => {
try {
const updateSong = await Song.findByIdAndUpdate(req.params.songId, req.body, { new: true });
res.redirect('/students/' + req.params.id + '/songs');
} catch (err) {
console.log(err);
}
});
I'm not sure what's causing the error here, my delete route is set up similarly and is working. Would appreciate any suggestions.
In your rote (req.params.id) is not defining.
songs.get('/:songId/edit', async (req, res) => {
try {
const findSong = Song.findById(req.params.songId);
**const findStudent = Student.findById = (req.params.id);**
const [foundSong, foundStudent] = await Promise.all([findSong, findStudent]);
res.render('songs/edit', {
student: foundStudent,
song: foundSong
})
} catch (err) {
console.log(err);
}
});