Mongoose MissingSchemaError happening inconsistently with Mocha test - javascript

In users.spec.js I have this and it works fine:
var mongoose = require('mongoose');
var assert = require('assert');
var request = require('supertest');
var app = require('../../app.js');
var User = mongoose.model('User');
var Local = mongoose.model('Local');
var agent = request.agent(app);
var invalidId = 'aaaaaaaaaaaaaaaaaaaaaaaa';
In app.js I have:
mongoose.connect(dbUrl);
var db = mongoose.connection;
db.on('error', console.error.bind(console, 'Problem connecting to database.'));
db.once('open', function onDbConnect() {
console.log('Connected to ' + dbUrl + ' database...');
// create models
require('./api/users/user.model.js');
And in user.model.js I have:
var User = mongoose.model('User', userSchema);
var Local = mongoose.model('Local', localSchema);
So when users.spec.js is run, it first creates the models, and then I can reference them by mongoose.model('User') and mongoose.model('Local').
However, in auth.spec.js, I'm doing the same thing, and it's not working:
var mongoose = require('mongoose');
var assert = require('assert');
var request = require('supertest');
var app = require('../../app.js');
var User = mongoose.model('User');
var Local = mongoose.model('Local');
var agent = request.agent(app);
Output:
/Users/azerner/code/mean-starter/node_modules/mongoose/lib/index.js:332
throw new mongoose.Error.MissingSchemaError(name);
^
MissingSchemaError: Schema hasn't been registered for model "User".
Use mongoose.model(name, schema)
at Mongoose.model (/Users/azerner/code/mean-starter/node_modules/mongoose/lib/index.js:332:13)
at Object.<anonymous> (/Users/azerner/code/mean-starter/server/api/auth/auth.spec.js:5:21)
Why is this? I'm running the tests separately: mocha server/api/auth and mocha server/api/users, so they shouldn't be interfering with one another.
Full code here.
Note: this works, but I'd prefer not to use it. Or at least I'd like to understand what the problem is and why this works.
// :( https://github.com/Automattic/mongoose/issues/1251
// it isn't exactly my issue, but the recommendation on the bottom works
try {
var User = mongoose.model('User');
var Local = mongoose.model('Local');
}
catch(e) {
var schemas = require('../users/user.model.js');
var User = mongoose.model('User', schemas.UserSchema);
var Local = mongoose.model('Local', schemas.LocalSchema);
}

Related

More than one connection opened in MongoDB using NodeJS and Mongoose

I am new to Node and MongoDB, so please forgive me if I sound too naive.
I have a DB class that creates a connection to MongoDB
db.service.js
const mongoose = require("mongoose");
const fs = require("fs");
const dbConfigs = JSON.parse(fs.readFileSync("/configs.json"));
const dbHost = dbConfigs.DB_HOST;
const dbName = dbConfigs.DB_NAME;
const dbPort = dbConfigs.DB_PORT;
const dbUrl = "mongodb://" + dbHost + ":" + dbPort + "/" + dbName;
const dbOptions = {
useNewUrlParser: true
};
let dbConnection = mongoose.createConnection(dbUrl, dbOptions);
exports.getConnection = () => {
if (dbConnection)
return dbConnection;
}
exports.closeConnection = () => {
if (dbConnection)
return dbConnection.close();
}
Next I have another module that creates a Schema for MongoDB
schema.js
const connection = require("./db.service").getConnection();
const Schema = require("mongoose").Schema;
const SampleSchema = new Schema({...})
exports.Sample = connection.model("Sample", SampleSchema);
Then I have another module that makes use of this Schema to save objects
logger.js
const Sample = require("./schema").Sample;
exports.log = () => {
let body = {....};
let sampleObj = new Sample(body);
return sampleObj.save(sampleObj);
The Main module
Main.js
const logger = require("./logger");
for (let i=0; i < 100; i++) {
logger.log();
}
When I run node Main.js, everything is saved, but when I check the MongoDB with the command db.serverStatus.connections, I see 6 connections open.
I don't know how it's getting there. I know the command mongo itself keep a connection open, but where are the other 5 connections coming from?
I have checked this, which seems to suggest that Mongoose opens 5 connections for an application, but my application is firing just one transaction, where is the need to open 5 connection then? Couldn't it be done with just one?
Mongoose is managing the connections itself; it tries to optimize the speed of the request.
You are seeing it like you are using only one transaction, but behind the scene mongoose is probably doing much more than you expect.
You can modify the number of connection mongoose can open using the parameter poolSize.
Example :
const dbOptions = {
useNewUrlParser: true,
poolSize: 1,
};
Try it with poolSize equals to 1 and see how much time it takes to execute your transaction, you'll have your answer.

Issues while trying to implement multi tenant system using node.js with mongodb

We have different clients and the idea is to keep their data separate from each other in the same application. We are using node.js with mongodb and mongoose is being used for querying.
This is 'index.js' file in models directory
var mongoose = require('mongoose');
var fs = require('fs');
var connectionUrl = 'mongodbserverlink/';
var companies = [{ db: 'comp1_db', comp_id: 'com1' }, { db: 'com2_db', comp_id: 'com2' }, { db: 'com3_db', compa_id: 'com3'}];
var connections = {};
var models = {};
fs.readdirSync(__dirname)
.forEach(function (file) {
var Schema = file.split('.js')[0];
if (Schema === 'index') return;
models[Schema] = require('./' + Schema);
});
companies.forEach(function (company) {
var conn = mongoose.createConnection(connectionUrl + company.db);
connections[company.company_id] = {};
Object.keys(models).forEach(function (Schema) {
connections[company.company_id][Schema] = conn.model(Schema, models[Schema]);
});
conn.on('error', console.error.bind(console, company.db + ' connection error in mongodb in the first step!'));
conn.once('open', function() {
console.log(company.db + " mongodb connected");
});
});
module.exports = connections;
Here the connection is being made with different databases. The models directory has this index file.
Now in the controller where application logic is being done, this is what we are doing.
var models = require('../models');
var comp_id = req.body.comp_id;
db.collectionname.find...(This is not the syntax for find, I just cut it short to keep it simple) // -> this is not working now
when we tried logging models object this is what we got
models object is: {"com1":{},"com2":{},"com3":{}}
and only db when logged gives {}
We are facing issues in grasping the complete work... it is because the person who wrote the major chunk is not with us and there is no documentation.
What are we doing wrong here?
It looks like you already have your models exported from the index file. So, in the controller you can do a var models = require('index');. From the connections object, you may be able to retrieve the corresponding model: var companyModel = models[comp_id];.
Hope it helps.

Cucumber + Mongoose is giving me Schema hasn't been registered for model

The error message:
MissingSchemaError: Schema hasn't been registered for model "User".
Use mongoose.model(name, schema)
at Mongoose.model (/Users/JimBarrows/Desktop/TaskVelocity/cucubmer/node_modules/mongoose/lib/index.js:349:13)
at Object.<anonymous> (/Users/JimBarrows/Desktop/TaskVelocity/cucubmer/features/support/hooks.js:3:21)
My world.js file:
/**stuff**/
var mongoose = require('mongoose');
mongoose.Promise = require('bluebird');
require('../../../public_ui/models/Users');
var User = mongoose.model('User');
mongoose.connect('mongodb://192.168.99.100:27017/task_velocity');
As I understand it, this should setup mongoose quite nicely. Then in hooks.js:
'use strict';
var mongoose = require('mongoose');
var User = mongoose.model('User');
I've tried, in the hooks.js file:
'use strict';
var mongoose = require('mongoose');
require('../../../public_ui/models/Users');
var User = mongoose.model('User');
but that gives me the same error when I try to get ahold of the model.
Any ideas on what I'm doing wrong?
Jim Barrows, considering that the error is:
MissingSchemaError: Schema hasn't been registered for model "User".
and that your world.js has the following lines:
require('../../../public_ui/models/Users');
var User = mongoose.model('User');
I believe that is just a typo error and you could fix it easily by doing the following:
var User = mongoose.model('Users'); // instead of var User = mongoose.model('User');
**which by the way is exactly what dafyk commented in your post (not an answer) some days ago...
Hope this helps
I'm not sure, but...
check this link
You have to make schema and set mongoose.model('User',schema);
Can you show me "Users.js" source?;
If you want make module,
like this source
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var UserSchema = new Schema({
username: String,
passwrod: String
//Have to Custom
});
module.exports = mongoose.model('User', UserSchema);
and use this
var Users = require('../../../public_ui/models/Users');

Schema method for all Schema's - Mongoose method inheritance

I'm working in nodejs with Mongoose, at this moment I have data in different collections with _id like string writing for the user, I try to make a refactor of this and generate _id automatically.
I want have in other file js only function generateID( return _id; ); and implement this function in all models without write over and over in all models.
This is bus.js
/***********************************Bus Model**********************************/
var mongoose = require('mongoose'),
merge = require('merge'),
global = require('./schema/global');
/***********************************Schema******************************************/
var Schema = mongoose.Schema;
var busSchema = new Schema({});
/***********************************Methods*****************************************/
var bus = mongoose.model('Bus', busSchema);
/**
* extend functions from global
* we do this to prevent duplicate code
*/
merge(bus.schema.methods, global.schema.methods);
module.exports = bus;
And this is global.js in schema folder over models folder in project
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
var globalSchema = new Schema({});
function objectIdAsString() {
return mongoose.Types.ObjectId().toString();
}
globalSchema.methods.objectIdAsString = objectIdAsString;;
module.exports = mongoose.model('global', globalSchema);
And in route.js have this implementation:
var bus = new Bus();
bus._id = bus.objectIdAsString();
Solution is creating a Mongoose plugin
http://mongoosejs.com/docs/plugins.html
global.js
var mongoose = require('mongoose');
module.exports = exports = function objectIdAsString(schema) {
schema.methods.objectIdAsString = function objectIdAsString() {
return mongoose.Types.ObjectId().toString();
};
}
bus.js
/***********************************Bus Model**********************************/
var mongoose = require('mongoose'),
merge = require('merge'),
global = require('./schema/global');
/***********************************Schema******************************************/
var Schema = mongoose.Schema;
var busSchema = new Schema({});
/**
* extend functions from global
* we do this to prevent duplicate code
*/
busSchema.plugin(global);
module.exports = mongoose.model('Bus', busSchema);
Somewhere else:
var bus = new bus();
console.log(bus.objectIdAsString());
Is working and outputting the correct values for me:
566b35a02a54c60e168c3a9f
566b35a02a54c60e168c3aa1
566b35a02a54c60e168c3aa3
.....

Node Js Module Layering

If you had a server js like so:
var app = require('express'),
http = require('http'),
news = require('./server/api/news'),
db = require('mongoose');
/* app config..... */
app.get('/api/news', news.list);
var server = http.createServer(app);
server.listen(app.get('port'), function () {
console.log("Server running");
});
And I wanted to create an API to handle adding news items to the database:
var db = require('mongoose');
/*** Public Interfaces ***/
function list(req, res) {
var offset = ~~req.query.offset || 0,
limit = ~~req.query.limit || 25;
db.News.find(function (err, newsItems) {
res.json(newsItems.slice(offset*limit, offset*limit + limit));
});
}
exports.list = list;
This API would exist in its own file, how do I use the instance of the db created in the server.js inside the new module.
Or do you create and open a new connection each time you query the database?
Thanks
I would probably do it more like this
the server :
var express = require('express'),
app = express(),
http = require('http'),
db = require('mongoose'),
news = require('./server/api/news')(db); // you can pass anything as args
app.get('/api/news', news.list);
/* add routes here, or use a file for the routes */
// app.get('/api/morenews', news.more_news); .... etc
http.createServer(app).listen(8000);
and in the ../news/index.js file or whatever you're using, I'd use a literal, but you can always use exports to pass back each method as well
module.exports = function(db) {
/* now db is always accessible within this scope */
return {
list : function (req, res) {
var offset = ~~req.query.offset || 0,
limit = ~~req.query.limit || 25;
db.News.find(function (err, newsItems) {
res.json(newsItems.slice(offset*limit, offset*limit + limit));
});
}, // now you can easily add more properties
more_news : function(req, res) {
res.end('Hello kitty');
}
}
}

Categories