Avoiding multiple instances of the Sequelize class - node.js

I'm trying to build out a basic database schema using Express and Sequelize. I define all of the models in separate files. I have a single file (models/index.js) where I create an instance of the Sequelize class, import the models, and establish the relationships among the models. I also have multiple controllers that each need to have access to the models exported from models/index.js.
Here's the file where the models are imported:
// models/index.js
var Sequelize = require('sequelize');
var sequelize = new Sequelize('myApp', 'username', 'password');
var User = sequelize.import('./users');
var Contact = sequelize.import('./contacts');
var Conversation = sequelize.import('./conversations');
var Medium = sequelize.import('./mediums');
User.hasMany(Contact);
Contact.belongsTo(User);
Contact.hasMany(Conversation);
Conversation.belongsTo(Contact);
Medium.hasMany(Conversation);
Conversation.belongsTo(Medium);
module.exports.Sequelize = Sequelize;
module.exports.sequelize = sequelize;
module.exports.User = User;
module.exports.Contact = Contact;
module.exports.Conversation = Conversation;
module.exports.Medium = Medium;
Here's one of the controllers that needs access to the models.
// controllers/users.js
var models = require('../models');
module.exports.addUser = function () {
};
module.exports.getUser = function () {
};
Here's another controller that needs access to the models.
// controllers/contacts.js
var models = require('../models');
module.exports.addContact = function () {
};
module.exports.getContact = function () {
};
module.exports.getAllContacts = function () {
};
My concern relates to the fact that both controllers require the models/index.js file. Each time the models/index.js file is required, a new instance of the Sequelize class is created, which establishes a new connection to the database. Does anybody have any suggestions to avoid multiple instances of the Sequelize class?
Thanks in advance!

Modules (files) are cached in node:
Modules are cached after the first time they are loaded. This means (among other things) that every call to require('foo') will get exactly the same object returned, if it would resolve to the same file.
Multiple calls to require('foo') may not cause the module code to be executed multiple times. This is an important feature. With it, "partially done" objects can be returned, thus allowing transitive dependencies to be loaded even when they would cause cycles.
If you want to have a module execute code multiple times, then export a function, and call that function.
https://nodejs.org/api/modules.html#modules_caching
This means, that the code on models/index.js will only be run once

Related

How to use same model file for two or more DB Connections

How to call multiple Database table in same Model JS File
Let's Say
var mongoose = require('./node_modules/mongoose');
mongoose.connect('mongodb://localhost/_db1');
module.exports = exports = mongoose;
// I know this overwrites
// Something like calling with different variable name
// Say mongoosedb1, mongoosedb2
// Still if do that we have to pass the library to both variables
// Any other possible ways??
mongoose.connect('mongodb://localhost/_db2');
module.exports = exports = mongoose;
I am not sure whether this is making sense, Could you anyone please give some suggestions, I am new to this MEAN Stack framework.
Thanks in Advance!!

How to avoid using global?

I have very small nodejs app. Inside this application I define a model object in app.js like so:
global.model = {
name: 'Foobar'
};
The model is not persisted to any storage but kept in memory all the time. My requirement is, to be able to read and modify this model inside any module of my app.
I read that it is bad practice to use global. What is the better way? Through exports? Can you explain?
You can have a single module that creates and stores the model. Then, any other module that wants to get the model can require() your model module and then call a method on it to fetch the single shared model.
in model.js:
var mymodel = {
name: 'Foobar'
}
module.exports.getModel = function() { return mymodel;}
in any other module that wants to get the model:
var mymodel = require('./model').getModel();
If your model module would not generally be used for other things, then you could simplify it like this:
var mymodel = {
name: 'Foobar'
}
module.exports = function() { return mymodel;}
in any other module that wants to get the model:
var mymodel = require('./model')();

Node.js - passing object with require

I am pretty certain there is a way to pass a variable using require.
So it would look something like this:
var model = require('model')(mongoose);
With the above line of code, I want to pass my model file my database information (mongoose), so that if I access the same model with a different database, I can pass it different database information.
However, even if the above syntax is correct, I am not sure what my model file itself would have to look like. Can anyone help me out with this?
module.exports = function (mongoose) {
// . . .
return model;
};
You can pass moongoose by argument to that file
var model = require('model')(mongoose);
Your module will look like this, you can make an object in module.exports and can attach multiple properties to that object and in the end return it from the function
module.exports = function (mongoose) {
model ={};
model.properties = {};
model.yourfunction1 = function(){};
return model;
};
I guess I can't assign anything else to module.exports in this case?
Answer to your comment is explained below
Choosing between module.exports and exports depends on you
For exports
exports.object1 = {};
exports.object2 = {};
For module.exports
module.exports = function(){
myobj={}
myobj.object1 = {};
myobj.object2 = {};
return myobj
}
Now calling it will be different
For exports it will be directly available on file variable
var file = require('./file');
console.log(file.object1);
For module.exports you will execute it like a function by appending function parenthesis so that object can be returned
var file = require('./file')();
console.log(file.myobj.object1);

Why doesn't my Mongoose schema method "see" my required object?

I'm really confused about a variable scope issue with a file required via a path in a config file. Why does my Mongoose schema method "see" the required objects when called from within the model file but not when called from my app.js file? I'm convinced that I must be doing something obviously wrong but I can't see it.
The Node project has the following (simplified) structure:
|models
-index.js
-story.js
-post.js
-app.js
-config.js
This is config.js:
config = {};
config.test = 'test';
config.models = __dirname + '/models';
module.exports = config;
This is story.js:
var config = require('../config.js');
var models = require(config.models);
var foo = {};
foo.bar = 'baz';
var storySchema = mongoose.Schema
({
author: {type: mongoose.Schema.Types.ObjectId},
root: {type: mongoose.Schema.Types.ObjectId, default: null}
});
storySchema.methods.test = function()
{
console.log(foo.bar);
console.log(config.test);
console.log(models);
}
var Story = exports.model = mongoose.model('story', storySchema);
When I create a new Story in app.js and call its test() method, I get this output:
baz (so I know it's seeing objects in the same file)
test (so I know it's seeing variables in the config file)
{} (this "should" log my models object but it logs an empty object, why?)
When I create a new Story object within the story.js file, and run it (node ./models.story.js) the values returned are as expected (the models object is logged rather than an empty object).
Update, here are the index.js and app.js files:
index.js:
module.exports = {
post: require('./post'),
story: require('./story')
};
app.js:
var config = require('./config');
var models = require(config.models);
var story = new models.story.model();
story.test();
I believe the issue is that you've created a circular dependency. Story executes require(config.models) which requires Story again inside index.js.
Rather than storing a string and requireing it everywhere, try storing the models directly in config.models:
config.js
module.exports = {
test: 'test',
models: require(__dirname + '/models')
};
In case anyone runs into this same issue, I wanted to point to a couple resources I came across that helped me resolve the issue. As ssafejava pointed out, the problem does have to do with circular dependency (although ssafejava's solution did not entirely resolve the issue) . What worked for me was designing this dependency out of my application but there are other options if doing so is not possible. See the following issues' comments for a better explanation (in particular, see 'isaacs' comments):
https://github.com/joyent/node/issues/1490
https://github.com/joyent/node/issues/1418

Method not found Error

I am new to node.js and mongo db. What I am trying to do is to call the ordered function in my model.js from index.js but I have a complain
object function model() has no method ordered()
routes/index.js
var pics_ = models.Picture.ordered();
model.js
Picture.prototype.ordered = function() {
var ordered = mongoose.Picture.find().sort({points:-1}).toArray()
console.log(ordered);
return ordered;
};
If you want to add methods to your models, you should use the Mongoose supported ways for doing that. See http://mongoosejs.com/docs/methods-statics.html

Resources