Express, Mongoose : OverwriteModelError : Cannot Overwrite 'xxxxx' model once compiled - node.js

I'm encoutering an error when using a Mongoose Model in my program.
I've did that in the beginning of my code :
var Schema = mongoose.Schema;
mongoose.connect('xxxxx');
I used a first schema called userSchema to connect/sign up a user.
I've this code, which should do a random on the field Bonus of my DB. But when I go to the randTest page, I have this error. How can I fix it ?
app.get('/randTest', function(req,res)
{
var bonusSchema = new Schema({
bonus : [String]
});
var bonusModel = mongoose.model('Plateau', bonusSchema);
var query = bonusModel.find(null);
query.exec(function (err, allBonus){
if(err) { throw err;}
var rand = Math.floor((Math.random() *allBonus.length));
var result = allBonus[rand-1];
});
res.render('randTest', {result: result});
});
In my Jade file I've just :
extends layout
block content
script.
alert({#result});

Move the bonusModel definition outside of app.get so that it's only called once:
var bonusSchema = new Schema({
bonus : [String]
});
var bonusModel = mongoose.model('Plateau', bonusSchema);
app.get('/randTest', function(req,res)
{
var query = bonusModel.find(null);
...
});

Related

Mongoose sub Docs CastError

I am new to MongoDB and MongooseJS. I'm also new to nodeJs.
I have an Angularjs project using Typescript. This project work with a "container" json, which itself contains some properties and a testList, which is a json object containing some properties and a fileList, containing an itemList.
So it's like this :
export class Container{
data:string="";
testList:Test[];
}
export class Test {
moredata:string="";
fileList:File[];
}
export class File {...}
etc.
I send this JSON to my nodejs server. I'm using bodyparser to get the json from the req.body object.
Server side, my mongoose Schema are exactly like my angularjs classes, so they look like this :
/*************** mongoose schemas **************/
// item.js
var mongoose = require('mongoose');
module.exports = mongoose.model('Item', {
Content : {type : Object, default: ''}
});
// file.js
var mongoose = require('mongoose');
var Item = require('./item');
var schema = new mongoose.Schema({
Data : {type : String, default: ''},
ItemList: {type: [Item], default:[]}
});
// test.js
var mongoose = require('mongoose');
var File = require('./file');
var schema = new mongoose.Schema({
Data: {type:String},
FileList: {type:[File], default:[]}
});
// container.js
var mongoose = require('mongoose');
var Test = require('./test');
var schema = new mongoose.Schema({
Name : {type : String, default: '', index:true, unique:true, required: true, dropDups:true},
Test : {type:[Test], default:[]}
});
If I try to create a new Container object (Mongoose object) and assign it the json from req.body, it bugs : CastError.
If I re-create each sub document from JSON and save the main doc, it bugs too : CastError.
I don't know how to achieve this. It worked before but my mongoose schema where using [mongoose.Schema.Types.Mixed] type for sub docs, and not the "real" types. Fact is, with Mixed I had no _id on sub docs, which I want.
Using real sub docs types, I can see in logs that the _id is created, but all the lists are empty.
Here is my nodejs code :
/*************** nodejs **************/
app.post('/api/container', bodyParser.urlencoded({extended:true}), bodyParser({limit:'50mb'}), bodyParser.json(), function(req, res) {
var test = req.body._test;
var testList = [];
var fileList;
var itemList;
var itemObj;
var fileObj;
var testObj;
for(var i in test){
fileList = [];
for(var j in test[i]._fileList){
itemList = [];
for(var k in test[i]._fileList[j]._itemList){
itemObj = new Item({
Content : test[i]._fileList[j]._itemList[k]._content
});
itemList.push(itemObj);
console.log('item pushed : ' + itemObj + ' and length : ' + itemList.length);
// logs gives info OK.
}
fileObj = new File({
Data: locales[i]._fileList[j]._data,
ItemList: itemList
});
fileList.push(fileObj);
console.log('file pushed : ' + fileObj);
// logs gives info NOK. The ItemList is empty : [], instead of a 70+ item list.
}
testObj = new Test({
Data: locales[i]._data,
FileList: fileList
});
testList.push(testObj);
console.log('test pushed : ' + i);
// once again, logs are NOK : the FileList is empty : []
}
// use mongoose to save the project in the database
new Container({
Name : req.body._name.toLowerCase().trim(),
Test: testList
}).save(function(err, container, count){
if(err){
console.log('erreur : ');
console.log(err);
// we enter here as we have this error :
/*
{ [CastError: Cast to undefined failed for value "
{
_id: 5727ebf95a76ff0011374928,
FileList: [],
Data: 'data'
},
{
_id: 5727ebf95a76ff0011374970,
FileList: [],
Data: 'other data'
}" at path "Test"]
message: 'Cast to undefined failed for value "
{ _id: 5727ebf95a76ff0011374928,\n FileList: [],\n Data: \'data\' },
{ _id: 5727ebf95a76ff0011374970,\n FileList: [],\n Data: \'other data\'}"
at path "Test"',
name: 'CastError',
type: undefined,
value: [{"_id":"5727ebf95a76ff0011374928","FileList":[],"Data":"data"},{"_id":"5727ebf95a76ff0
011374970","FileList":[],"Data":"other data"}],
path: 'Test' }
*/
res.status(403).json({error: 'error'});
} else {
console.log('saved ! ');
res.json(container);
}
});
});
I'm not used to post here, I'm more a reader :) Anyway if my post is not appropriated please inform me and I'll move / edit it correctly.
Thanks for your time.
Checked, and working !
So my error was to use the models of my objects in mongoose schema instead of their Schema.
I'm now exporting both models and schema on each object, and using schema for schema definitions, and models for requests. Finally rid of this bug ! :)
/* Mongoose object definitions */
// grab the mongoose module
var mongoose = require('mongoose');
var child = require('./child').schema; // getting the child schema
// define our parent model
var parentSchema = new mongoose.Schema({
Name : {type : String, default: ''},
ChildrenList: {type: [Child], default:[]}
});
var parentModel = mongoose.model('Parent', parentSchema);
// module.exports allows us to pass this to other files when it is called
module.exports = {
model: parentModel, // exporting model for requests
schema: parentSchema // exporting schema for others schema using "Parent"
};
And the code used for requests :
var Child = require('./models/child').model; // here using model
var Parent = require('./models/parent').model; // here using model
new Parent({
Name : req.body._name.toLowerCase().trim(),
ChildrenList : childrenList // variable defined somewhere
}).save(function(err, parent, count){
if(err){
res.status(403).json({error: 'too bad'});
} else {
res.json(parent);
}
});

Nodejs undefined var when separate code in models [duplicate]

This question already has answers here:
Reference error on node.js while include file
(2 answers)
Closed 6 years ago.
I'm writting my first nodejs app, and i'm getting an error when i move a piece of code to an external js file. the code i'm trying to move is a mongodb schema declaration:
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
//--------------------users ------------
var usersSchema = new Schema({
email: String,
name: String,
phoneNumber: String,
BirthDate: Date,
loginpwd:String
});
var UserModel = mongoose.model('users', usersSchema);
I'm using filesystem module to load the external file:
fs.readdirSync(__dirname+'/models').forEach(function(filename){
if (~filename.indexOf('.js'))
require(__dirname+'/models/'+ filename);
console.log(filename+" added");
});
the following block does not work well when I separate the code, throwing an "undefined UserModel" error:
var userData = new UserModel({email : req.body.edtEmail,
name: req.body.edtName,
phoneNumber: req.body.edtPhoneNumber,
BirthDate: req.body.edtBirthDate,
loginpwd: req.body.edtSenha});
// save user data to database
userData.save(function(err, record){
if(err) throw err;
// session setting
req.session.userEmail = req.body.edtEmail;
req.session.name = req.body.edtName;
req.session.phoneNumber = req.body.edtPhoneNumber;
req.session.birthDate = req.body.edtBirthDate;
req.session.userId = record._id;
res.redirect('/dashboard');
});
the following code works well in both inline code or "in file" code:
app.get('/users/json', function(req, res){
mongoose.model('users').find(function(err, users){
res.send(users);
});
});
Am I doing something wrong when load external file ? or missing something ?
There is a build in system in nodeJs to load files.
I am not really sure what you want to do but in nodejs you would do something like this
//Lets say this file is called UserModel.js
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
//-------------------- rest of you code ------------
var UserModel = mongoose.model('users', usersSchema);
module.exports = UserModel; //this is important
Than in a another file you could just load this
var UserModel = require('UserModel');
var bob = new UserModel({ ....
so you can work with your UserModel. Read maybe the docs about require
Also can use like:
in your schema file: (say directory "models/userModel.js")
...
mongoose.model('UserModel', usersSchema);
in controller or other file where you want to use: (say directory "controller/userController.js")
require('../models/userModel');// load user model
var mongoose = require('mongoose'),
UserModel = mongoose.model('UserModel'),
var userData = new UserModel({email : req.body.edtEmail, //rest of code...});
userData.save(function(err, record){ //rest of code ...
and can use for route like: (follow like as controller)
app.get('/users/json', function(req, res){
UserModel.find(function(err, users){
res.send(users);
});
});

Mongoose saving for populate

I'm new to Mongoose and Nodejs developement in general and I've got a bit of confusion around how to properly set up saving my records. Here are my two schemas:
Download
var mongoose = require("mongoose");
var Schema = mongoose.Schema;
var downloadSchema = Schema({
title : String,
description : String,
_project : { type: Schema.Types.ObjectId, ref: 'Project' }
});
module.exports = mongoose.model('Download', downloadSchema);
Project
...
var projectSchema = Schema({
name : String,
url : String,
pwd : String,
_downloads : [{type: Schema.Types.ObjectId, ref: 'Download' }]
});
module.exports = mongoose.model('Project', projectSchema);
This appears to be working correctly. The documentation explains my use-case of saving a download and linking a project, but I'm not sure how to properly populate the Project._downloads. Here's what I've done:
Express route handler:
function createDownload(req, res) {
// the Project Id is passed in the req.body as ._project
var dldata = req.body;
Project.findOne({ _id : dldata._project }, function(err, project) {
var dload = new Download(dldata);
dload.save( function (err, download) {
project._downloads.push(download._id);
project.save( function(err){
var msg = {};
if(err) {
msg.status = 'error';
msg.text = err;
}else {
msg.status = 'success';
msg.text = 'Download created successfully!';
}
res.json(msg);
});
});
});
}
This seems overcomplicated to me. Am I supposed to be manually pushing to the ._downloads array, or is that something Mongoose is supposed to handle internally based on the schema? Is there a better way to achieve it so that I can do:
Download.find().populate('_project').exec( ...
as well as:
Project.findOne({_id : _projectId}).populate('_downloads').exec( ...
According to the mongoose docs there are 2 ways to add subdocs to the parent object:
1) by using the push() method
2) by using the create() method
So I think that your code can be a bit simplified by eliminating the operation of saving a new Download item:
function createDownload(req, res) {
var dldata = req.body;
Project.findOne({ _id : dldata._project }, function(err, project) {
// handle error
project._downloads.push(dldata);
project.save(function(err) {
// handle the result
});
});
}
or
function createDownload(req, res) {
var dldata = req.body;
Project.findOne({ _id : dldata._project }, function(err, project) {
// handle error
project._downloads.create(dldata);
project.save(function(err) {
// handle the result
});
});
}

Using mongoose and Q.spread gives array callback parameters

I have the code below:
var mongoose = require('mongoose');
var Q = require("q")
mongoose.connect("mongodb://localhost/testdb");
var Schema = mongoose.Schema;
var employeeSchema = new Schema({
name:String
})
var Employee = mongoose.model('Employee', employeeSchema);
var departmentSchema = new Schema({
name:String
})
var Department = mongoose.model('Department', departmentSchema);
var employee = new Employee();
employee.name = "T.Smith";
var dept = new Department();
dept.name = "Sales";
Q.spread([
Q.nfcall(employee.save.bind(employee)),
Q.nfcall(dept.save.bind(dept))
],function(emp,dept){
console.log(JSON.stringify(emp));
console.log(JSON.stringify(dept));
mongoose.disconnect();
})
The log statements will yield the results below:
[{"__v":0,"name":"T.Smith","_id":"5358f3c53cd354bc70fe619f"},1]
[{"__v":0,"name":"Sales","_id":"5358f3c53cd354bc70fe61a0"},1]
Why are the results an array instead of a single object?
I get the same if i replace the last block of code with this block:
Q.all([
Q.nfcall(employee.save.bind(employee)),
Q.nfcall(dept.save.bind(dept))
]).spread(function(emp,dept){
console.log(JSON.stringify(emp));
console.log(JSON.stringify(dept));
mongoose.disconnect();
})
By the way, which block is recommended?
The save callback signature is function(err, result, numberAffected) which doesn't conform to node callback convention. nfcall expects a node callback signature, which is function(err, result). To avoid loss of information, the promise returned by nfcall resolves to [result, numberAffected].
Using .bind and Q.nfcall at call sites is very ugly anyway, so you can create a method that does all this:
mongoose.Model.prototype.saveForResult = function() {
return Q.nbind(this.save, this)().spread(function(result, numberAffected) {
return result;
});
};
Then:
Q.spread([
employee.saveForResult(),
dept.saveForResult()
],function(emp,dept){
console.log(JSON.stringify(emp));
console.log(JSON.stringify(dept));
mongoose.disconnect();
})

How to save element into collection with out defining in schema

I am trying to add an element into schema object in a middleware pre save method, I defined the config as strict: false. So expecting this new element to be added and saved to the object. Below is my code which I am working on.
var mongoose = require('mongoose');
var connection = mongoose.connect('mongodb://localhost/my_database');
var Schema = mongoose.Schema
var User = new Schema({
author : String
, type : String
}, { strict: false });
var MyUserModel = mongoose.model('User', User); //create and access the model User
var u = new MyUserModel({author:'mark',type:'novel'});
u.pre('save', function(next, req){
var self = this;
self.view = 'ALL';
console.log("pre save");
next();
});
u.save(function(err){
if (err) console.log(err);
});
The problem is unable to save the new element(view) into the collection.
You need to use set:
self.set('view', 'ALL');
For properties that aren't in the schema, Mongoose cannot create a setter (whereas for properties that are in the schema, it does, and so self.author = '...' would work), so you have to set it explicitly.

Resources