How to organize a node app that uses sequelize? - node.js

I am looking for an example nodejs app that uses the sequelize ORM.
My main concern is that it seems next to impossible to define your models in separate js files if those models have complex relationships to one another because of require() dependency loops. Maybe people define all their models in one file that is very very long?
I am mainly interested in how the models are defined and use through out the app. I would like to have some validation that what i am doing on my own is the "good" way to do things.

The short story
The trick in this case is not to initialize the model in the file but just to provide the necesary information for its initialization and let a centralized module take care of the models setup and instantiation.
So the steps are:
Have several Model files with data about the model, like fields, relationships and options.
Have a singleton module which loads all those files and setup all the model classes and relationships.
Setup your singleton module at the app.js file.
Get the model classes from the singleton module do not use require on your model files, load the models from the singleton instead.
The longer story
Here is a more detailed description of this solution with the corresponding source code:
http://jeydotc.github.io/blog/2012/10/30/EXPRESS-WITH-SEQUELIZE.html
EDIT: This is a very old answer! (read down for info)
It's old and limited in many ways!
First, as #jinglesthula mentioned in comments (and I experienced it too) - there are problems with requiring those files. It's because require doesn't work the same way as readdirSync!
Second - you are very limited in relations - the code doesn't provide options to those associations so you are UNABLE to create belongsToMany as it needs through property. You can make the most basic assocs.
Third - you are very limited in model relations! If you read closely the code, you will see that relations is an Object instead of an Array, so if you want to make more than one associations of the same type (like having two times belongsTo) - you cannot!
Fourth - You don't need that singleton thingy. Every module in nodejs is singleton by itself, so all this makes is pretty complex for no reason.
You should see Farm's answer! (The link to the article is broken, but I'll fix it with this official sample from sequelize: https://github.com/sequelize/express-example/blob/master/models/index.js - you can browse the whole project to get an idea of what's going on).
p.s.
I'm editing this post as it's so upvoted that people won't even see any new answers (as I did).
Edit: Just changed the link to a copy of the same post, but in a Github Page

SequelizeJS has a article on their website which solves this problem.
Link is broken, but you can find the working sample project here and browse it. See edited answer above to see why this is a better solution.
Extract from article:
models/index.js
The idea of this file is to configure a connection to the database and to collect all Model definitions. Once everything is in place, we will call the method associated on each of the Models. This method can be used to associate the Model with others.
var fs = require('fs')
, path = require('path')
, Sequelize = require('sequelize')
, lodash = require('lodash')
, sequelize = new Sequelize('sequelize_test', 'root', null)
, db = {}
fs.readdirSync(__dirname)
.filter(function(file) {
return (file.indexOf('.') !== 0) && (file !== 'index.js')
})
.forEach(function(file) {
var model = sequelize.import(path.join(__dirname, file))
db[model.name] = model
})
Object.keys(db).forEach(function(modelName) {
if (db[modelName].options.hasOwnProperty('associate')) {
db[modelName].options.associate(db)
}
})
module.exports = lodash.extend({
sequelize: sequelize,
Sequelize: Sequelize
}, db)

I've create a package sequelize-connect to help people deal with this issue. It follows the Sequelize suggested convention here: http://sequelize.readthedocs.org/en/1.7.0/articles/express/
Additionally it also functions a bit more like Mongoose in terms of its interface. It allows you to specify a set of locations where your models are located and also allows you to define a custom matching function to match your model files.
The usage is basically like this:
var orm = require('sequelize-connect');
orm.discover = ["/my/model/path/1", "/path/to/models/2"]; // 1 to n paths can be specified here
orm.connect(db, user, passwd, options); // initialize the sequelize connection and models
Then you can access the models and sequelize like so:
var orm = require('sequelize-connect');
var sequelize = orm.sequelize;
var Sequelize = orm.Sequelize;
var models = orm.models;
var User = models.User;
Hopefully this helps someone out.

I started using Sequelize in Express.js app. Soon enough ran into issues of the nature you're describing. Maybe I did not quite understand Sequelize, but to me doing things more than just selecting from one table wasn't really convenient. And where ordinarily you would use select from two or more tables, or a union in pure SQL, you would have to run separate queries, and with the async nature of Node it's just added complexity.
Therefore I moved away from using Sequelize. Moreover I am switching from using ANY data fetching from DB in the models. In my opinion it is better to abstract getting data completely. And reasons are - imagine that you don't just use MySQL (in my case, I use MySQL and MongoDB side by side), but you can get your data from any data provider and any transport method, e.g. SQL, no-SQL, filesystem, external API, FTP, SSH etc. If you tried to do all of it in the models, you would eventually create complex and hard to understand code that would be hard to upgrade and debug.
Now what you want to do is to have models get data from a layer that knows where and how to get it, but your models only use API methods, e.g. fetch, save, delete etc. And inside this layer you have specific implementations for specific data providers. E.g. you can request certain data from a PHP file on a local machine or from Facebook API or from Amazon AWS or from remote HTML document, etc.
PS some of these ideas were borrowed from Architect by Cloud9: http://events.yandex.ru/talks/300/

I set it up as Farm and the documentation describe.
But I was having the additonal problem that in my instance methods and class methods that I would attach to the models in each function I would need to require the index file to get a hold of other database objects.
Solved it by making them accessible to all models.
var Config = require('../config/config');
var fs = require('fs');
var path = require('path');
var Sequelize = require('sequelize');
var _ = require('lodash');
var sequelize;
var db = {};
var dbName, dbUsername, dbPassword, dbPort, dbHost;
// set above vars
var sequelize = new Sequelize(dbName, dbUsername, dbPassword, {
dialect: 'postgres', protocol: 'postgres', port: dbPort, logging: false, host: dbHost,
define: {
classMethods: {
db: function () {
return db;
},
Sequelize: function () {
return Sequelize;
}
}
}
});
fs.readdirSync(__dirname).filter(function(file) {
return (file.indexOf('.') !== 0) && (file !== 'index.js');
}).forEach(function(file) {
var model = sequelize.import(path.join(__dirname, file));
db[model.name] = model;
});
Object.keys(db).forEach(function(modelName) {
if ('associate' in db[modelName]) {
db[modelName].associate(db);
}
});
module.exports = _.extend({
sequelize: sequelize,
Sequelize: Sequelize
}, db);
And in the model file
var classMethods = {
createFromParams: function (userParams) {
var user = this.build(userParams);
return this.db().PromoCode.find({where: {name: user.promoCode}}).then(function (code) {
user.credits += code.credits;
return user.save();
});
}
};
module.exports = function(sequelize, DataTypes) {
return sequelize.define("User", {
userId: DataTypes.STRING,
}, { tableName: 'users',
classMethods: classMethods
});
};
I only did this for the class methods but you could also do the same thing for instance methods.

I am following the official guide: http://sequelizejs.com/heroku, which has a models folder, set up each module in separate files, and have a index file to import them and set the relationship among them.

Sample model sequelize
'use strict';
const getRole = require('../helpers/getRole')
const library = require('../helpers/library')
const Op = require('sequelize').Op
module.exports = (sequelize, DataTypes) => {
var User = sequelize.define('User', {
AdminId: DataTypes.INTEGER,
name: {
type: DataTypes.STRING,
validate: {
notEmpty: {
args: true,
msg: 'Name must be filled !!'
},
}
},
email: {
type: DataTypes.STRING,
validate: {
notEmpty: {
args: true,
msg: 'Email must be filled !!'
},
isUnique: function(value, next) {
User.findAll({
where:{
email: value,
id: { [Op.ne]: this.id, }
}
})
.then(function(user) {
if (user.length == 0) {
next()
} else {
next('Email already used !!')
}
})
.catch(function(err) {
next(err)
})
}
}
},
password: {
type: DataTypes.STRING,
validate: {
notEmpty: {
args: true,
msg: 'Password must be filled !!'
},
len: {
args: [6, 255],
msg: 'Password at least 6 characters !!'
}
}
},
role: {
type: DataTypes.INTEGER,
validate: {
customValidation: function(value, next) {
if (value == '') {
next('Please choose a role !!')
} else {
next()
}
}
}
},
gender: {
type: DataTypes.INTEGER,
validate: {
notEmpty: {
args: true,
msg: 'Gender must be filled !!'
},
}
},
handphone: {
type: DataTypes.STRING,
validate: {
notEmpty: {
args: true,
msg: 'Mobile no. must be filled !!'
},
}
},
address: DataTypes.TEXT,
photo: DataTypes.STRING,
reset_token: DataTypes.STRING,
reset_expired: DataTypes.DATE,
status: DataTypes.INTEGER
}, {
hooks: {
beforeCreate: (user, options) => {
user.password = library.encrypt(user.password)
},
beforeUpdate: (user, options) => {
user.password = library.encrypt(user.password)
}
}
});
User.prototype.check_password = function (userPassword, callback) {
if (library.comparePassword(userPassword, this.password)) {
callback(true)
}else{
callback(false)
}
}
User.prototype.getRole = function() {
return getRole(this.role)
}
User.associate = function(models) {
User.hasMany(models.Request)
}
return User;
};

You can import models from other files with sequelize.import
http://sequelizejs.com/documentation#models-import
That way you can have one singleton module for sequelize, which then loads all the other models.
Actually this answer is quite similar to user1778770`s answer.

I am looking for an example nodejs app that uses the sequelize ORM.
You might be interested in looking at the PEAN.JS boilerplate solution.
https://github.com/StetSolutions/pean
PEAN.JS is a full-stack JavaScript open-source solution, which provides a solid starting point for PostgreSQL, Node.js, Express, and AngularJS based applications.
The PEAN project is a fork of the MEAN.JS project (not to be confused with MEAN.IO or the generic MEAN stack).
https://github.com/meanjs/mean
PEAN replaces MongoDB and the Mongoose ORM with PostgreSQL and Sequelize. A primary benefit of the MEAN.JS project is the organization it provides to a stack that has many moving pieces.

You can also use a dependency injection which provides an elegant solution to this. Here's one https://github.com/justmoon/reduct

What worked for me is to:
Create a file for each individual model like user.model.js in folder models/user.model.js.
Create index.js in models/index.js and import every model to it.
Define association, run sync method in index.js and export all models.
Create a database.js file that holds information about Sequalize and import it and initialize it in app.js
Example of one models/user.model.js
import { DataTypes } from 'sequelize';
import { sequelize } from '../database.js';
export const User = sequelize.define("user",{
uid:{
type:DataTypes.STRING,
allowNull:false,
unique: true
},
email:{
type:DataTypes.STRING,
allowNull:true
},
firstName:{
type:DataTypes.STRING,
allowNull:true
},
lastName:{
type:DataTypes.STRING,
allowNull:true
},
companyWebsite:{
type:DataTypes.STRING,
allowNull:true
},
domain:{
type:DataTypes.STRING,
allowNull:true
},
hsPortalId:{
type:DataTypes.INTEGER,
allowNull:true
},
integrations:{
type:DataTypes.STRING
},
brandedKeywords : {
type:DataTypes.STRING
},
companyName: {
type:DataTypes.STRING
},
companyStreet:{
type:DataTypes.STRING
},
companyZip:{
type:DataTypes.STRING
},
companyCountry:{
type:DataTypes.STRING
},
vatId:{
type:DataTypes.STRING
},
brand:{
type:DataTypes.STRING
},
markets:{
type:DataTypes.JSON
},
niche : {
type:DataTypes.JSON
}
},{schema:"api"})
Example of models/index.js
import { Billing } from './billing.model.js';
import { Competitor } from './competitors.model.js';
import { DemoAccount } from './demo.model.js';
import { Notification } from './notification.model.js';
import { Product } from './products.model.js';
import { Reseller } from './resellers.model.js';
import {Reseller_User} from './reseller_user.model.js'
import { Tag } from './tags.model.js';
import {User} from './user.model.js'
Reseller.belongsToMany(User, { through: Reseller_User });
User.belongsToMany(Reseller, { through: Reseller_User });
// this will create a UserId column on your Product table
// https://www.youtube.com/watch?v=HJGWu0cZUe8 40min
User.hasMany(Product,{onDelete: 'CASCADE',})
Product.belongsTo(User)
User.hasOne(DemoAccount,{onDelete: 'CASCADE',})
DemoAccount.belongsTo(User)
User.hasMany(Billing,{onDelete: 'CASCADE',})
Billing.belongsTo(User)
User.hasMany(Tag,{onDelete: 'CASCADE',})
Tag.belongsTo(User)
User.hasMany(Competitor,{onDelete: 'CASCADE'})
Competitor.belongsTo(User)
User.hasMany(Notification,{onDelete: 'CASCADE'})
Notification.belongsTo(User)
User.sync().then(
() => console.log("Sync complete")
);
Reseller.sync().then(
() => console.log("Sync complete")
);
Reseller_User.sync().then(
() => console.log("Sync complete")
);
Product.sync().then(
() => console.log("Product Sync complete")
);
Competitor.sync().then(
() => console.log("Competitor Sync complete")
);
Notification.sync().then(
() => console.log("Competitor Sync complete")
);
Billing.sync().then(
() => console.log("Billing Sync complete")
);
Tag.sync().then(
() => console.log("Tag Sync complete")
);
DemoAccount.sync()
export { User, Reseller, Product, Competitor, Notification, DemoAccount, Billing, Tag };
// DemoAccount.sync({force:true}).then(
// () => console.log("Sync complete")
// );

Related

Node.JS TypeError: result.setPet is not a function

So, I'm new to Node.JS, and this project is a simple petshop, with pets table, services offered, and appointments (when a certain service is applied to a certain pet in a certain date in the future).
Appointments have a petId and serviceId, each appointment must have only one of those, but pets and services can be referenced in multiple appointments.
This project was originally made with pure MySql, with separate repositories to handle queries, later I changed it to use sequelize ORM.
I've made the basics crud operations using the rest architecture, everything ok with the services and pets methods (post, get, patch, delete), but the problem began when trying to make post method with appointments, since appointments have serviceId and petId.
index.js
const customExpress = require('./config/customExpress');
const connection = require('./infrastructure/database/connection');
connection.sync()
.then(() => {
console.log('Successfully connected to database')
const app = customExpress()
app.listen(3000, () => console.log('Server running at port 3000'))
})
.catch(erro => console.log('Something went wrong while trying to synchronize to database'))
connection.js
here is where the associations between tables and models are made, I think the error might be here, but can't figure out where
const Sequelize = require('sequelize')
const config = require('config')
const { applyExtraSetup } = require('../../models/extraSetup')
const sequelize = new Sequelize(
config.get('mysql.database'),
config.get('mysql.user'),
config.get('mysql.password'),
{
host:config.get('mysql.host'),
dialect:config.get('mysql.dialect')
}
)
const modelDefiners = [
require('../../models/appointments'),
require('../../models/pets'),
require('../../models/services'),
]
// it gets the models definitions and pass the above instance of sequelize to them
for (const modelDefiner of modelDefiners){
modelDefiner(sequelize)
}
// and then make their relations with extra setup
applyExtraSetup(sequelize)
.then(module.exports = sequelize)
the extraSetup.js, makes the relations
// it exports the things the sequelize instance must do
async function applyExtraSetup(sequelize){
const { appointments, services, pets } = sequelize.models
await appointments.belongsTo(services)
await appointments.belongsTo(pets)
await services.hasMany(appointments)
await pets.hasMany(appointments)
}
module.exports = { applyExtraSetup }
and this is appointment.js, a controller that handles the /appointments route and call the sequelize methods
app.post('/appointment', async (req, res) => {
const data = req.body
const pet = await Pets.findAll({ where : { name : req.body.petId }})
const service = await Service.findAll({ where : { name : req.body.serviceId }})
const appointment = Appointment.create(data)
.then(result => {
result.setPet(pet)
res.end()
})
reading sequelize documentation, I saw that with this type of association, you get magic methods to handle data from the related tables, which you call from an instance of a model (setPet, getPet, and so on).
Can anyone help me?
edit, models definitions (they're together since I'm refactoring the code, but originally each one was in a separate module):
exports.appointment = (sequelize) => {
const now = new Date()
const Appointment = sequelize.define('appointments', {
client: {
type: DataTypes.STRING,
allowNull: false
},
creationDate: {
type: DataTypes.DATE,
allowNull: false,
defaultValue: now
},
date: {
type: DataTypes.DATE,
allowNull: false,
validate: {
isBefore: now
}
},
status: {
type: DataTypes.STRING,
allowNull: false
},
observations: {
type: DataTypes.STRING
}
})
return Appointment
}
exports.pets = (sequelize) => {
const Pets = sequelize.define('pets', {
name : {
type: DataTypes.STRING,
allowNull: false
},
image: {
type: DataTypes.STRING,
allowNull: false
},
})
return Pets
}
exports.service = (sequelize) => {
const Service = sequelize.define('services', {
name: {
type: DataTypes.STRING,
allowNull: false
},
price: {
type: DataTypes.FLOAT,
allowNull: false
}
})
return Service
}

How to create common CRUD operations in Express using Sequelize?

I want to create common crud operations in Express js with Sequelize.
I have created getAll function as below.
exports.getAll = (module, res,next) => {
module
.findAndCountAll({
where: {
CreatedBy: 1,
isDeleted: false,
isActive: true
},
offset: 0,
limit: 10,
}).then((result) => {
res.status(200).json({
message: "data Fetched from database",
statusCode: 200,
result: result,
});
}).catch((error) => {
console.log(error);
});
}
and I am calling this common function in Controller function as below by passing name of Model e.g. category
crudOperations.getAll(category, res);
It is working fine. but how do I create function for post data ?
For posting data, I want to use Sequelize's magic methods (because one user can associated with many category as below)
user.hasMany(category, {
foreignKey: 'CreatedBy'
});
Example, I want to add category with respect to user, so I want to use magic method as below.
req.user
.createCategory({
name: name,
})
How should I pass user and createCategory as parameter to common function?
How do I pass data to function?
Is it good practice to create common function for CRUD? or should go with writing function for each module?
I am building application architecture and design. When we are talking about creating common methods or services, it would completely depend on the use case or types of operation we are performing.
Sequelize has already basic methods which perform common operations. Following is my idea which might put more light on your way. Please refer to below pseudo-code.
Answer 1.
Following is the method that might help you, that how do you organize your functions. It is my basic thought, so there might room for an error.
BaseModel.helper.js
class BaseModelHelper{
static async find(params){
const {model, where, attributes, include=[] offset:0, limit: 10} = params;
objFind = {};
if(Object.keys(where).length > 0){
objFind = {...objFind, where}
}
if(attributes.length > 0){
objFind = {...objFind, attributes}
}
if(include.length > 0){
objFind = {...objFind, include}
}
model.find({
where: where,
attributes: attributes,
include,
offset,
limit
}).then((data)=>{
return data;
}).catch((err)=>{
throw new Error(err);
});
}
static async create(params){
const {model, properties} = params;
model.create(properties)
.then((data)=>{
return data;
}).catch((err)=>{
throw new Error(err);
});
}
static async update(params){
const {model, newData, where} = params;
model.update(newData, {
where
})
.then((data)=>{
return data;
}).catch((err)=>{
throw new Error(err);
});
}
static async delete(params){
const {model, where} = params;
model.destroy(where)
.then((data)=>{
return data > 0 ? true : false;
}).catch((err)=>{
throw new Error(err);
});
}
}
module.exports = BaseModelHelper;
Data.services.js
const BaseModelHelper = require("BaseModel.helper.js);
class DataServices{
static async add(){
// Owner table entry
const {id} = await BaseModelHelper.create({
model: "Owner'
properties:{
name: 'Loren',
role: 'admin',
},
});
// Cat table entry
const {id: petId} = await BaseModelHelper.create({
model: "Pet'
properties:{
owner_id: 'c0eebc45-9c0b',
type: 'cat',
}
});
}
static async findWithRelations(){
const arrData = await BaseModelHelper.find({
model: 'User',
where: {
role: 'admin'
},
attributes: ['id', 'username', 'age'],
include: [{
model: pet,
through: {
attributes: ['createdAt', 'startedAt', 'finishedAt'],
where: {completed: true}
}
}]
});
}
static async findBelongs(){
const arrData = await BaseModelHelper.find({
model: 'User',
where: {
role: 'admin'
},
attributes: ['id', 'username', 'age']
});
}
static async update(){
const arrData = await BaseModelHelper.update({
Model: 'Pet',
newData:{
name: 'lina',
}
where: {
name: 'suzi',
}
});
}
static async delete(){
const arrData = await BaseModelHelper.delete({
Model: 'Pet',
where: {
name: 'lina',
}
});
}
}
module.exports = DataServices;
The above way I have described has one benefit is to you don't go to do error handling every place, if you have to manage to centralize error handler. An when an error occurred it throws an error and catches by centralizing the error handler of Express.
The above class of common db operation is build based on my experience and the frequency of the operations we have performed. I know that there is room for more possibilities than we expect, but with the method, I have suggested you might not face many obstacles.
Answer 2. You should create a whole qualified query object at your service level. Once its build at the service level, then only you will pass it to our BaseModelHelper.
Answer 3. Same thing you should create your data object at the service level. If the data object builds from multiple tables, then you first encapsulate at the service level, then you should pass to the BaseModelHelper method.
Answer 4. Yes, I also favor the same. But one thing you should keep in mind that there is always room for improvement. If you wish to create a method for each module then you should copy this BaseModelHelper to everywhere else I suggest inheriting the file at the service level.
All the database operation objects build at the service level, not the controller level. Your database service and object preparation services might be different so it will give a more clear picture. The object preparation service might scope to include more different services.
Again above approach is my thought process and I suggested you based on my experience. Again there is more room for improvement, that you might take to create.

Sequelize Association in class methods not working

I'm trying to set associations in class methods but it's not working as it should!
const User = sequelize.define('User', {
email: DataTypes.STRING,
password: DataTypes.STRING,
}, {
classMethods: {
associate: (models) => {
User.hasMany(models.AnotherModel, {foreignKey: 'userId'});
},
}
});
But when i set associations outside of classMethods block it works:
User.associate = function (models) {
User.hasMany(models.AnotherModel, {foreignKey: 'userId'});
};
why the codes inside classMethods block not working?
sequelize version: 4.2.0
This is an expected behavior, the classmethod syntax refers to sequelize version < 4.
Since v4, sequelize has evolved more towards js class syntax and hence the change.
The upgrade manual here details more about it
with "sequelize": "5".
Used this on my code to develop OSE server in Peru:
'use strict';
module.exports = (sequelize, DataTypes) => {
const UserModel = sequelize.define('user', {
user: DataTypes.STRING,
password: DataTypes.STRING,
description: DataTypes.STRING
}, {});
UserModel.associate = function (models) {
// associations can be defined here
};
UserModel['getHashName'] = () => {
return 'UserCache';
};
UserModel['getCacheKey'] = () => {
return 'user';
};
UserModel['getCacheValue'] = () => {
return 'password';
};
return UserModel;
};
and well, the next call :
console.log(User.getHashName());
console.log(User.getCacheKey());
console.log(User.getCacheValue());
Remember when library owners would leave the old method in place for a period of time, have it report that it's deprecated, but still operate so when we revisit a three year old project, and have zero idea why bringing the code forward breaks the entire universe, we might could get some direction on a resolution? I remember those days. Heady, wonderful days, those.
We're in the middle of a large code-forward update, bringing an old application to the modern versions of Node, et al, and holy crap, everything is just flat out broken. This'll be fun.
Digging in, this is "expected behavior", but wow, what a horrible way to learn about it. :(

Sequelize bulk synchronization does nothing

I'm unable to get sequelize.sync() to work. Calling sync() on each model definition works flawlessly but calling it from the sequelize instance appears do to nothing, like if the model manager had no registered models in it.
Consider the following:
function syncAll() {
console.log('Retrieving exported models...')
let models = require('./models')
for(var modelName in models) {
let model = models[modelName]
// define() just wraps a regular sequelize.define() call
// model.define().sync() works!
model.define()
}
console.log('All exported models have been defined! Syncing database...')
sequelize.sync({
logging: true
}).then(function() {
// The operation completes but no command is executed in the DB
console.log('Database synchronization complete!')
}).catch(function(error) {
console.log("Database synchronization error:\n\t${error}")
})
}
Just trying to understand what I'm missing, why bulk synchronization isn't working for me?
AFAIK I just need all models defined before calling sequelize.sync(), right?!
EDIT 1
Some info about my environment: I'm using node 5.6 under debian with postgres
EDIT 2
Found the problem. Refer to end of the accepted answer...
This code from sequelize example works fine for me:
var sequelize = new Sequelize(config.database, config.username, config.password, config);
var db: any = {};
var Task = sequelize.define("Task", {
title: Sequelize.STRING
}, {
classMethods: {
associate: function(models) {
Task.belongsTo(models.User, {
onDelete: "CASCADE",
foreignKey: {
allowNull: false
}
});
}
}
});
var User = sequelize.define("User", {
username: Sequelize.STRING
}, {
classMethods: {
associate: function(models) {
User.hasMany(models.Task);
}
}
});
db.User = User;
db.Task = Task;
Object.keys(db).forEach(function(modelName) {
if ("associate" in db[modelName]) {
db[modelName].associate(db);
}
});
sequelize.sync().then(() => {
// some code here
});
Models have been defined via "sequelize.define(...)" and after that "sequelize.sync()" has been called.
Update 1
I'm using sqlite:
var config: any = {
"dialect": "sqlite",
"storage": "./db.development.sqlite"
};
Update from OP
I've spotted the only diference between this code and mine. Due to a bug in my logic sequelize.define() and sequelize.sync() were being called from different sequelize instances (i.e different connections) and each connection has its own modelManager so obviously there was no models to sync in the second connection object.

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