Nodejs with Sequelizejs using separate files per model - node.js

This is an embarrassingly beginner question, but I just want to settle my worries about Sequelizejs. I want to split out each model into its own file to keep my source organized. In order to do that I need to require("sequelize') and var sequelize = new Sequelize('DB-Name', 'DB-User', 'DB-Password'); at the start of each file.
My question is, will that create a new connection to the database per model, or will it just keep re-using the same connection? Should I abandon the whole concept of "one model per file" and just create a master Models.js file?
I am very new to Node and am still getting used to its conventions. Thanks for the help!

Every model is defined as its own module, which you export:
module.exports = function(sequelize, DataTypes){
return sequelize.define('Brand', {
name: {
type: DataTypes.STRING,
unique: true,
allowNull: false },
description: {
type: DataTypes.TEXT,
allowNull: false },
status: {
type: DataTypes.INTEGER,
unique: false,
allowNull: true }
})
};
Then simply import the module when you initialize Sequelize (and you can import many models here):
var Sequelize = require("sequelize");
var config = require("../../config/config.js");
var sequelize = new Sequelize(config.database, config.username, config.password,
{ dialect: config.dialect, host: config.host, port: config.port,
omitNull: true, logging: false });
var Brand = require("./Brand").Brand;
You can read up more on modules at http://nodejs.org/api/modules.htm but the example above should get you started.

In case if one wants to use EcmaScript 6 approach there is great example with explanation in Sequelize documentation here.
// in your server file - e.g. app.js
const Project = sequelize.import(__dirname + "/path/to/models/project")
// The model definition is done in /path/to/models/project.js
// As you might notice, the DataTypes are the very same as explained above
module.exports = (sequelize, DataTypes) => {
return sequelize.define("project", {
name: DataTypes.STRING,
description: DataTypes.TEXT
})
}
The import method can also accept a callback as an argument.
sequelize.import('project', (sequelize, DataTypes) => {
return sequelize.define("project", {
name: DataTypes.STRING,
description: DataTypes.TEXT
})
})

Related

Sequelize defining tables pluralized when using sync

I've written migrations to define my tables in a seperate service. Im then using a node.js service to run sequelize where i'm defining my models like this:
import Sequelize from "sequelize";
import sequelize from "../config/sequelize";
export const MasterPlaylist = sequelize.define("Master_playlist", {
id: { type: Sequelize.STRING, primaryKey: true },
updated_at: {
type: Sequelize.DATE,
defaultValue: new Date(),
allowNull: false,
},
});
Im then importing this and calling it like so:
import Sequelize from "sequelize";
import sequelize from "./config/sequelize";
import { Label } from "./models/Label";
async function run(){
await sequelize.sync();
const label = await Label.findOne();
console.log("done", label);
}
run()
Have simplified things slightly here, but this is whats being run.
When i run this it creates new tables but pluralised so i end up with the correctly named tables as inserted by the migrations and then pluralised copies.
For example for this table i end up with 'Master_playlists'
Anyone got an idea whats happening here?
here is my config file:
import Sequelize from "sequelize";
const sequelize = new Sequelize(
process.env.DB,
process.env.USERNAME,
process.env.PASSWORD,
{
host: process.env.HOST,
dialect: "postgres",
}
);
async function run() {
await sequelize.authenticate();
}
run();
export default sequelize;
Not exactly sure what the issue is, but sequelize uses inflection to pluralize table names.
By default, when the table name is not given, Sequelize automatically pluralizes the model name and uses that as the table name. This pluralization is done under the hood by a library called inflection, so that irregular plurals (such as person -> people) are computed correctly.
You can control the table names directly using freezeTableName: true which will keep the table name the same as model name:
sequelize.define('User', {
// ... (attributes)
}, {
freezeTableName: true
});
or specify the table name explicitly:
sequelize.define('User', {
// ... (attributes)
}, {
tableName: 'users'
});

Sequelize() doesn't return an instance of sequelize

I recently started using Sequelize to get a model of my postgresql database.
To map the database I am using sequelize-auto.
I was able to create an auto generated mapping of my db using sequelize-auto when I sent my arguments this way to its constructor:
init.js
let sequelizeAutoInstance = new SequelizeAuto(dbName,username,password,options)
But it doesn't work when I try to send an instance of Sequelize this way:
new-init.js
let sequelizeInstance = new Sequelize(sequelizeOptions);
sequelizeAutoInstance = new SequelizeAuto(sequelizeInstance)
Looking into sequelize-auto ctor I saw it runs those lines:
if (database instanceof Sequelize) {
this.sequelize = database;
}
but the instance returning form new Sequelize doesn't return an instance of Sequelize.
What did I miss?
thanks
If I got you correct. You need to pass an instance of sequelize to your models. If you are using extension models you can simply pass in the instance into the init options.
const { Sequelize, DataTypes, Model } = require('sequelize');
const sequelize = require("../your/db/file");
class User extends Model {}
User.init({
// Model attributes are defined here
firstName: {
type: DataTypes.STRING,
allowNull: false
},
lastName: {
type: DataTypes.STRING
// allowNull defaults to true
}
}, {
// Other model options go here
sequelize, // We need to pass the connection instance
modelName: 'User' // We need to choose the model name
});
if its functional then
const { Sequelize, DataTypes } = require('sequelize');
const sequelize = require("../your/db/file");
const User = sequelize.define('User', {
// Model attributes are defined here
firstName: {
type: DataTypes.STRING,
allowNull: false
},
lastName: {
type: DataTypes.STRING
// allowNull defaults to true
}
}, {
// Other model options go here
});
All this can be found in the Sequelize models documentation

"defineCall is not a function". Using sequelize with Node.JS

I'm learning how to use Sequelize for a Node.JS project, I'm working on the models:
index.js
var Sequelize = require('sequelize');
const sequelize = new Sequelize('mysql://bf3a13a7df5b2f:e2707ede#us-cdbr-iron-east-03.cleardb.net/heroku_6bdb0d8ad6c6a50?reconnect=true');
// load models
var models = [
'student',
];
models.forEach(function(model) {
module.exports[model] = sequelize.import(__dirname + '/' + model);
});
// export connection
module.exports.student= student;
module.exports.sequelize = sequelize;
student.js
var sequelize = require('./dbConnection');
var Sequelize = require('sequelize');
const student = sequelize.define('student', {
id: {
type: Sequelize.STRING,
primaryKey: true
},
name: {
type: Sequelize.STRING
},
middleName: {
type: Sequelize.STRING
},
lastName: {
type: Sequelize.STRING
},
dob: {
type: Sequelize.DATE
},
//student.sync({force: true});
});
module.exports = student;
and this is the error message I receive from the command line:
C:\Users\adria\OneDrive\Documentos\GitHub\ScholarMean1\node_modules\sequelize\lib\sequelize.js:691
this.importCache[path] = defineCall(this, DataTypes);
^
TypeError: defineCall is not a function
I managed to make it work if the model is in index.js, but because I want to make a file for each model I hope you can help me.
I saw a similar problem just now and the problem was a file that was in the models folder that was not actually a database model. Ensure that your models folder only contains models for your database. Hopefully this helps!

Where should I store my data models?

I use sqlight to create a datamodel in a node-module:
database.js:
var Sequelize = require('sequelize'),
settings = require('./settings.js').settings,
sequelize = new Sequelize(settings.database),
//Datamodel
User = sequelize.define('user', {
authID: Sequelize.STRING,
name: Sequelize.STRING,
}),
UserAttribute = sequelize.define('userAttributes', {
name: Sequelize.STRING,
value: Sequelize.STRING,
}),
Hail = sequelize.define('hail', {
lat: Sequelize.INTEGER,
lon: Sequelize.INTEGER,
});
UserAttribute.belongsTo(User);
Hail.belongsTo(User, {as: 'driver'});
Hail.belongsTo(User, {as: 'rider'});
sequelize.sync(settings.sync).then(function() {
return User.create({});
}).then(function(driver) {
console.log(driver.get({
plain: true
}));
});
This works fine, but what if I want to access the models in another part of my application, like if I would like to create a user inside a controller. Where should i store them and what would be a good way of doing that?
A common way of organizing apps having Sequelize models is creating a models package with index.js inside handling association and reading the models inside the package directory. Example:
sequelize/express-example
Also see #Farm's answer in this thread:
How to organize a node app that uses sequelize?

sequelize .create is not a function error

I'm getting Unhandled rejection TypeError: feed.create is not a function error and I can't understand why it occurs. What's the problem here?
Here's my code. I'm probably not doing something very fundamental here since I can't reach feed variable in routes/index.js.
If I add module.exports = feed; to my models file, I can reach it, but I have more than one models, so if I add additional models below the feed, they override it.
db.js
var Sequelize = require('sequelize');
var sequelize = new Sequelize('mydatabase', 'root', 'root', {
host: 'localhost',
dialect: 'mysql',
port: 8889,
pool: {
max: 5,
min: 0,
idle: 10000
},
define: {
timestamps: false
}
});
var db = {};
db.sequelize = sequelize;
db.Sequelize = Sequelize;
module.exports = db;
models.js
var db = require('./db'),
sequelize = db.sequelize,
Sequelize = db.Sequelize;
var feed = sequelize.define('feeds', {
subscriber_id: Sequelize.INTEGER,
activity_id: Sequelize.INTEGER
},
{
tableName: 'feeds',
freezeTableName: true
});
routes/index.js
var express = require('express');
var router = express.Router();
var models = require('../models');
router.get('/addfeed', function(req,res) {
sequelize.sync().then(function () {
return feed.create({
subscriber_id: 5008,
activity_id : 116
});
}).then(function (jane) {
res.sendStatus(jane);
});
});
You cannot reach a variable from a file, by only requiring it in another one. You need to either define an object literal to hold all your variables in one place and assign it to module.exports, or you need to import them from different files separately.
In your case, I would create separate files to hold table schemas, and then import them by sequelize.import under one file, then require that file.
Like this:
models/index.js:
var sequelize = new Sequelize('DBNAME', 'root', 'root', {
host: "localhost",
dialect: 'sqlite',
pool:{
max: 5,
min: 0,
idle: 10000
},
storage: "SOME_DB_PATH"
});
// load models
var models = [
'Users',
];
models.forEach(function(model) {
module.exports[model] = sequelize.import(__dirname + '/' + model);
});
models/Users.js
var Sequelize = require("sequelize");
module.exports=function(sequelize, DataTypes){
return Users = sequelize.define("Users", {
id: {
type: DataTypes.INTEGER,
field: "id",
autoIncrement: !0,
primaryKey: !0
},
firstName: {
type: DataTypes.STRING,
field: "first_name"
},
lastName: {
type: DataTypes.STRING,
field: "last_name"
},
}, {
freezeTableName: true, // Model tableName will be the same as the model name
classMethods:{
}
},
instanceMethods:{
}
}
});
};
Then import each model like this:
var Users = require("MODELS_FOLDER_PATH").Users;
Hope this helps.
Just use
const { User } = require("../models");
Update :
in newer version of sequelize v6 and beyond sequelize.import is deprecated
sequelize docs recommend using require now
If you have generated models using migrations
this is how your model file will look like
models/user.js
'use strict'
module.exports = (sequelize, DataTypes, Model) => {
class User extends Model {
/**
* Helper method for defining associations.
* This method is not a part of Sequelize lifecycle.
* The `models/index` file will call this method automatically.
*/
static associate(models) {
// define association here
}
};
User.init({
name: {
type: DataTypes.STRING,
allowNull: false
},
phone_number: {
type: DataTypes.STRING(20)
},
otp: {
type: DataTypes.INTEGER(4).UNSIGNED
},{
sequelize,
modelName: 'User',
});
return User;
};
as you can see your model export function has sequelize DataTypes & Model parameters.
so when you import this model you should send above arguments.
Example
I am importing user model in controllers/user.js file, it could be any file
controllers/controller.js
const Sequelize = require('sequelize');
const sequelize = require('../config/db').sequelize;
// Bring in Model
const User = require('../models/user')(sequelize, Sequelize.DataTypes,
Sequelize.Model);
// your code...
// User.create(), User.find() whatever
Notice that sequelize(with small 's') and Sequelize(with capital 'S') are different things, first one represent instance of Sequelize created using new Sequelize, second one is just package you installed & imported
first one (sequelize) can be found wherever you started a connection to database using const sequelize = new Sequelize() usually from app.js or db.js file, make sure to export it from there and import it into where you want to use Model i.e controller
export sequelize instance
db.js Or app.js
const sequelize = new Sequelize();
... //your code
...
module.exports = {
sequelize: sequelize
}
You may want to check the answer given on the link below tackling the same issue, I was able to resolve mine using const User = sequelize.import('../models/users');, instead of just import User from '../models/users';
Sequelize create not a function?
I came with the same issue when I used something like:
const { Feed } = require("../models/Feed.js");
So, just using the code down below solved it
const { Feed } = require("../models");

Resources