I am trying to create an index on an existing table (Postgres) on a date column so that I can get the latest posts first
Model file feeditem.js
module.exports = (sequelize, DataTypes) => {
const FeedItem = sequelize.define('FeedItem', {
feedItemId: {
//...
},
pubdate: {
allowNull: false,
type: DataTypes.DATE,
validate: {
isDate: true,
notEmpty: true,
},
},
link: {
//...
},
title: {
//...
},
description: {
//...
},
summary: {
//...
},
author: {
//...
},
hash: {
//...
},
}, {
timestamps: false,
underscored: true,
indexes: [
{
fields: [{ attribute: 'pubdate', order: 'DESC' }],
unique: false,
},
],
});
FeedItem.associate = (models) => {
// associations can be defined here
//...
};
return FeedItem;
};
Migration file create-feed-item.js
module.exports = {
up: (queryInterface, Sequelize) => queryInterface.createTable('feed_items', {
feed_item_id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER,
},
pubdate: {
allowNull: false,
type: Sequelize.DATE,
},
link: {
allowNull: false,
type: Sequelize.STRING,
},
title: {
allowNull: false,
type: Sequelize.STRING,
},
description: {
type: Sequelize.TEXT,
},
summary: {
type: Sequelize.TEXT,
},
author: {
type: Sequelize.STRING,
},
hash: {
allowNull: false,
type: Sequelize.UUID,
unique: true,
},
}),
// eslint-disable-next-line no-unused-vars
down: (queryInterface, Sequelize) => queryInterface.dropTable('feed_items'),
};
Migration file add-index.js
module.exports = {
/*
Add altering commands here.
Return a promise to correctly handle asynchronicity.
Example:
return queryInterface.createTable('users', { id: Sequelize.INTEGER });
*/
// eslint-disable-next-line no-unused-vars
up: (queryInterface, Sequelize) => queryInterface.addIndex('feed_items', ['pubdate'], {
fields: [{
attribute: 'pubdate', order: 'DESC',
}],
unique: false,
name: 'feed_items_pubdate_index',
}),
/*
Add reverting commands here.
Return a promise to correctly handle asynchronicity.
Example:
return queryInterface.dropTable('users');
*/
// eslint-disable-next-line no-unused-vars
down: (queryInterface, Sequelize) => queryInterface.removeIndex('feed_items', 'feed_items_pubdate_index'),
};
The migrations are run in perfect order where table is created first and index is added later.
Logging is enabled and when I check the logs
Expected:
It should create a DESC index on pubdate which goes like
CREATE INDEX "feed_items_pubdate_index" ON "feed_items" ("pubdate" DESC)
Actual Output
Executing (default): CREATE INDEX "feed_items_pubdate_index" ON "feed_items" ("pubdate")
Any ideas what is going wrong here?
Your question is still relevant because it is undocumented.
The proper way to define index in descending order is extended definition in fields argument.
So the migration file add-index.js should look like:
module.exports = {
...
up: (queryInterface, Sequelize) => queryInterface.addIndex(
'feed_items',
[{
attribute: 'pubdate', order: 'DESC',
}],
{
unique: false,
name: 'feed_items_pubdate_index',
}
),
...
};
Resolved issue reference.
use uniqueKeys:
'use strict';
module.exports = {
up: (queryInterface, Sequelize) => {
return queryInterface.createTable('Users', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER
},
name: {
allowNull: true,
type: Sequelize.STRING
},
order: {
allowNull: false,
type: Sequelize.INTEGER
},
createdAt: {
allowNull: false,
type: Sequelize.DATE
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE
}
},
{
uniqueKeys: {
actions_unique: {
fields: ["name", "order"],
},
},
}
);
},
down: (queryInterface, Sequelize) => {
return queryInterface.dropTable('Users');
}
};
Related
I have this model:
'use strict';
const { Model } = require('sequelize');
module.exports = (sequelize, DataTypes) => {
class Superhero 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 ({ Image, Superpower }) {
// define association here
Superhero.hasMany(Image, { foreignKey: 'superheroId' });
Superhero.hasMany(Superpower, { foreignKey: 'superheroId' });
}
}
Superhero.init(
{
nickname: {
allowNull: false,
type: DataTypes.STRING(128),
validate: { notEmpty: true, notNull: true, len: [1, 128] },
},
realName: {
allowNull: false,
field: 'real_name',
type: DataTypes.STRING(128),
validate: {
notEmpty: true,
notNull: true,
len: [1, 128],
},
},
originDescription: {
allowNull: false,
field: 'origin_description',
type: DataTypes.TEXT,
validate: {
notEmpty: true,
notNull: true,
},
},
superpowers: {
allowNull: false,
type: DataTypes.TEXT,
validate: {
notEmpty: true,
notNull: true,
},
},
catchPhrase: {
allowNull: false,
field: 'catch_phrase',
type: DataTypes.STRING,
validate: {
notEmpty: true,
notNull: true,
len: [1, 255],
},
},
images: {
allowNull: false,
type: DataTypes.TEXT,
validate: {
notNull: true,
notEmpty: true,
},
},
},
{
sequelize,
modelName: 'Superhero',
underscored: true,
tableName: 'superheroes',
}
);
return Superhero;
};
I have such a superpower migration:
'use strict';
module.exports = {
async up (queryInterface, Sequelize) {
await queryInterface.createTable('superpowers', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER,
},
superheroId: {
field: 'superhero_id',
allowNull: false,
type: Sequelize.INTEGER,
references: {
model: {
tableName: 'superheroes',
},
key: 'id',
},
onDelete: 'cascade',
onUpdate: 'cascade',
},
superpowerName: {
field: 'superpower_name',
allowNull: false,
type: Sequelize.STRING,
},
createdAt: {
allowNull: false,
type: Sequelize.DATE,
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE,
},
});
},
async down (queryInterface, Sequelize) {
await queryInterface.dropTable('superpowers');
},
};
When I try to run this command npx sequelize db:migrate, I get an error
Sequelize CLI [Node: 16.14.2, CLI: 6.4.1, ORM: 6.21.0]
Loaded configuration file "src/config/db.json".
Using environment "development".
== 20220704175320-create-superpower: migrating =======
ERROR: relation "superheroes" does not exist
What could be the reason?
I have a hunch that the superpower table is trying to spawn before the superhero table.
Thus, when creating a table with a superpower, an attempt is made to link the "superheroId" field in the superpower table with the "id" field in the superhero table, which does not exist yet.
P.S. If necessary, the file structure looks something like this:
UPD. Migration with superhero:
'use strict';
const { Model } = require('sequelize');
module.exports = (sequelize, DataTypes) => {
class Superhero 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 ({ Image, Superpower }) {
// define association here
Superhero.hasMany(Image, { foreignKey: 'superheroId' });
Superhero.hasMany(Superpower, { foreignKey: 'superheroId' });
}
}
Superhero.init(
{
nickname: {
allowNull: false,
type: DataTypes.STRING(128),
validate: { notEmpty: true, notNull: true, len: [1, 128] },
},
realName: {
allowNull: false,
field: 'real_name',
type: DataTypes.STRING(128),
validate: {
notEmpty: true,
notNull: true,
len: [1, 128],
},
},
originDescription: {
allowNull: false,
field: 'origin_description',
type: DataTypes.TEXT,
validate: {
notEmpty: true,
notNull: true,
},
},
superpowers: {
allowNull: false,
type: DataTypes.TEXT,
validate: {
notEmpty: true,
notNull: true,
},
},
catchPhrase: {
allowNull: false,
field: 'catch_phrase',
type: DataTypes.STRING,
validate: {
notEmpty: true,
notNull: true,
len: [1, 255],
},
},
images: {
allowNull: false,
type: DataTypes.TEXT,
validate: {
notNull: true,
notEmpty: true,
},
},
},
{
sequelize,
modelName: 'Superhero',
underscored: true,
tableName: 'superheroes',
}
);
return Superhero;
};
I believe that your syntax is off in the "references" object. The model property should be a string or a static model.
references: {
model: 'superheroes'
key: 'id'
}
Documentation link
I'm trying to realize the query, where I can find all records, which at least one of the attributes includes the text, user send with request, for that I use where, but it can search, as I understand, in only own model, but i need it to search it in parent model and in associated filds together, not apart.
There is my models:
const Picture = sequelize.define<IPictureInstance>('picture', {
id: { type: DataTypes.INTEGER, primaryKey: true, autoIncrement: true },
img: { type: DataTypes.STRING, allowNull: false },
mainTitle: { type: DataTypes.STRING, allowNull: false },
description: { type: DataTypes.TEXT }
});
const PictureInfo = sequelize.define<IPictureInfoInstance>('pictureInfo', {
id: { type: DataTypes.INTEGER, primaryKey: true, autoIncrement: true },
title: { type: DataTypes.STRING, allowNull: false },
description: { type: DataTypes.STRING, allowNull: false }
});
const PictureTag = sequelize.define<IPictureTagInstance>('pictureTag', {
id: { type: DataTypes.INTEGER, primaryKey: true, autoIncrement: true },
text: { type: DataTypes.TEXT, allowNull: false }
});
const PicturesTags = sequelize.define<IPicturesTagsInstance>('picturesTags', {
id: { type: DataTypes.INTEGER, primaryKey: true, autoIncrement: true }
});
And their associations:
Picture.belongsToMany(PictureTag, { through: PicturesTags, as: "tags", onDelete: 'cascade' });
PictureTag.belongsToMany(Picture, { through: PicturesTags, as: "pictures", onDelete: 'cascade'
});
Picture.hasMany(PictureInfo, { onDelete: "cascade" });
PictureInfo.belongsTo(Picture);
That's what I tried to do:
static async getPictures(query: string | undefined) {
const pictures = await models.Picture.findAll({
where: {
[Op.or]: {
mainTitle: { [Op.iRegexp]: `${query}` },
description: { [Op.iRegexp]: `${query}` },
},
},
include: [
{
model: models.PictureInfo,
as: "pictureInfos",
where: {
[Op.or]: {
title: { [Op.iRegexp]: `${query}` },
description: { [Op.iRegexp]: `${query}` }
}
},
required: false
},
{
model: models.PictureTag,
as: "tags",
attributes: ["id", "text"],
where: { text: { [Op.iRegexp]: `${query}` } },
through: {
attributes: [],
},
required: false
}
],
});
return pictures;
}
But in this case, when it can't find records in first where param it returns an empty array, I understand it, but it isn't a behavior I need.
I need to check every attribute together.
So, if user send query=cat, it will check mainTitle and description, if there is nothing, it will check associated pictureInfos fields and after, if there is nothing, check pictureTags associated fields, that's what I need, will be grateful for the help.
My solution:
static async getPictures(query: string | undefined) {
const whereStatement = {
[Op.or]: {
mainTitle: { [Op.iRegexp]: `${query}` },
description: { [Op.iRegexp]: `${query}` },
"$tags.text$": { [Op.iRegexp]: `${query}` },
"$pictureInfos.title$": { [Op.iRegexp]: `${query}` },
"$pictureInfos.description$": { [Op.iRegexp]: `${query}` },
}
};
const pictures = await models.Picture.findAll({
where: whereStatement,
include: [
{
model: models.PictureInfo,
as: "pictureInfos",
},
{
model: models.PictureTag,
as: "tags",
}
],
});
return pictures;
}
But I'm still confused with those $ symbols, what they are for, I couldn't find the answer in documentation?
Link to the Sequelize documentation, to confirm my answer
I have 2 models that I am associating like this. Customer is associated to application by 1:M relationship.
customer:
'use strict';
module.exports = (sequelize, DataTypes) => {
let customer = sequelize.define('customer', {
id: {
type: DataTypes.INTEGER,
allowNull: false,
primaryKey: true,
autoIncrement: true
},
name: {
type: DataTypes.STRING
},
account_id: {
type: DataTypes.STRING
},
code: {
type: DataTypes.STRING
},
createdAt: {
type: DataTypes.DATE,
defaultValue: sequelize.literal('NOW()')
},
updatedAt: {
type: DataTypes.DATE,
defaultValue: sequelize.literal('NOW()')
}
},
{
underscored: true,
freezeTableName: true,
tableName: 'customer'
});
customer.associate = function(models) {
// associations can be defined here
customer.hasMany(models.application, { foreignKey:
'customer_id' });
};
sequelize.sync()
.then(() => customer.create(
{ name: "customer1", account_id: "cust-1-acct-1", code: "ACME Inc." }
)).then(function(customer) {
console.log('customers created');
}).then(() => customer.create(
{ name: "customer2", account_id: "cust-2-acct-2", code: "test Cust" }
)).then(function(customer) {
console.log('customers created');
})
.catch(function(err) {
console.log(err);
});
return customer;
}
application:
'use strict';
module.exports = (sequelize, DataTypes) => {
let application = sequelize.define('application', {
id: {
type: DataTypes.INTEGER,
allowNull: false,
primaryKey: true,
autoIncrement: true
},
name: {
type: DataTypes.STRING,
sortable: true
},
creation_date: {
type: DataTypes.NUMERIC,
sortable: true
},
customer_id: {
type: DataTypes.INTEGER
},
createdAt: {
type: DataTypes.DATE,
defaultValue: sequelize.literal('NOW()')
},
updatedAt: {
type: DataTypes.DATE,
defaultValue: sequelize.literal('NOW()')
}
},
{
underscored: true,
freezeTableName: true,
tableName: 'application'
});
application.associate = function(models) {
// associations can be defined here
application.belongsTo(models.customerView, { through: 'customer_id' });
};
sequelize.sync()
.then(() => application.create(
{ customer_id: "1", name: "application 1", creation_date: "1556724178700" }
)).then(() => application.create(
{ customer_id: "1", name: "application 2", creation_date: "1556724178700" }
)).then(() => application.create(
{ customer_id: "2", name: "application 3", creation_date: "1556724178700" }
))
.then(function(application) {
console.log('applications created');
})
.catch(function(err) {
console.log(err);
});
return application;
}
These 2 tables are getting created as expected, but without the foreign key constraint that I am expecting. The foreign key should be on the application table, on customer_id.
What am I doing wrong?
I'm not understanding why sequelize is giving me this error.
relation "Likes" does not exist
I referenced a similar question, but it didn't provide me with much of an insight:
Sequelize Error: Relation does not exist
and this too:
Sequelize Migration: relation <table> does not exist
My table names matches the reference model names.
I don't think it has anything to do with the models, but everything to do with the migrations file.
This is what I have
Posts migration
'use strict';
module.exports = {
up: (queryInterface, Sequelize) => {
return queryInterface.createTable('Posts', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER
},
title: {
type: Sequelize.STRING
},
post_content: {
type: Sequelize.STRING
},
createdAt: {
allowNull: false,
type: Sequelize.DATE
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE
},
userId: {
type: Sequelize.INTEGER,
references: {
model: 'Users',
key: 'id'
}
},
likeId: {
type: Sequelize.INTEGER,
onDelete: 'CASCADE',
references: {
model: 'Likes',
key: 'id'
}
},
username: {
type: Sequelize.STRING
},
});
},
down: (queryInterface, Sequelize) => {
return queryInterface.dropTable('Posts');
}
};
Likes migration
'use strict';
module.exports = {
up: (queryInterface, Sequelize) => {
return queryInterface.createTable('Likes', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER
},
like: {
type: Sequelize.BOOLEAN
},
userId: {
type: Sequelize.INTEGER,
references: {
model: 'Users',
key: 'id',
as: 'userId'
}
},
postId: {
type: Sequelize.INTEGER,
references: {
model: 'Posts',
key: 'id',
as: 'postId'
}
},
createdAt: {
allowNull: false,
type: Sequelize.DATE
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE
}
});
},
down: (queryInterface, Sequelize) => {
return queryInterface.dropTable('Likes');
}
};
models/like.js
'use strict';
const Like = (sequelize, DataTypes) => {
const Likes = sequelize.define('Likes', {
like:{
type:DataTypes.BOOLEAN,
allowNull:true
}
}, {});
Likes.associate = function(models) {
Likes.belongsTo(models.User, {
onDelete: "CASCADE",
foreignKey: {
foreignKey: 'userId'
}
})
Likes.belongsTo(models.Post, {
onDelete: 'CASCADE',
foreignKey: 'likeId',
targetKey: 'id',
})
}
return Likes;
};
module.exports = Like;
models/post.js
module.exports = (sequelize, DataTypes) => {
const Post = sequelize.define('Post', {
title: DataTypes.STRING,
post_content: DataTypes.STRING,
username: DataTypes.STRING
}, {});
Post.associate = function(models) {
Post.belongsTo(models.User, { foreignKey: 'userId', targetKey: 'id' });
Post.belongsTo(models.Likes, { foreignKey: 'likeId', targetKey: 'id' });
};
return Post;
};
models/user.js
'use strict';
const User = (sequelize, DataTypes) => {
const myUser = sequelize.define('User', {
username: DataTypes.STRING,
email: DataTypes.STRING,
password: DataTypes.STRING,
resetPasswordToken:DataTypes.STRING,
resetPasswordExpires: DataTypes.DATE
}, {});
myUser.associate = function(models) {
myUser.hasMany(models.Post, { foreignKey: 'userId', as:'users' });
myUser.hasMany(models.Likes, { foreignKey: 'userId', as:'likes' });
};
return myUser;
};
module.exports = User;
Instead of adding likeId in the migration. I needed to add a new migration like so
sequelize migration:generate --name add_likeId_to_posts
so we have now
'use strict';
module.exports = {
up: function (queryInterface, Sequelize) {
return queryInterface.addColumn(
'Posts',
'likeId',
{
type: Sequelize.INTEGER,
allowNull: false,
references: {
model: 'Likes',
key: 'id'
}
}
)
},
down: function (queryInterface, Sequelize) {
return queryInterface.removeColumn(
'Posts',
'likeId'
)
}
};
which gives us
voila!
and likeId is Associated on the table
I'm using Sequelize to make this request:
return Expense.findAll({
include: [{
model: ExpenseCategory
}],
})
.then(expenses => res.status(200).send(expenses))
.catch(error => res.status(500).send({ error: error }));
and I'm getting this error:
SequelizeEagerLoadingError
I can't seem to find my error.
This are my migrations for the three models (User, Expense, ExpenseCategory):
queryInterface.createTable('Users', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER
},
email: {
allowNull: false,
type: Sequelize.STRING,
unique: true
},
passhash: {
allowNull: false,
type: Sequelize.STRING
},
currency: {
type: Sequelize.STRING,
defualt: 'lev'
},
createdAt: {
allowNull: false,
type: Sequelize.DATE
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE
}
});
queryInterface.createTable('Expenses', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER
},
value: {
allowNull: false,
type: Sequelize.FLOAT
},
text: {
type: Sequelize.STRING
},
expenseCategoryId: {
allowNull: false,
type: Sequelize.INTEGER,
references: {
model: 'ExpenseCategories',
key: 'id'
},
onDelete: 'cascade'
},
userId: {
allowNull: false,
type: Sequelize.INTEGER,
references: {
model: 'Users',
key: 'id'
},
onDelete: 'cascade'
},
createdAt: {
allowNull: false,
type: Sequelize.DATE
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE
}
});
queryInterface.createTable('ExpenseCategories', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER
},
category: {
allowNull: false,
type: Sequelize.STRING
},
createdAt: {
allowNull: false,
type: Sequelize.DATE
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE
}
});
and the model definitions:
const User = sequelize.define('User', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: DataTypes.INTEGER
},
email: {
allowNull: false,
type: DataTypes.STRING,
unique: true
},
passhash: {
allowNull: false,
type: DataTypes.STRING
},
currency: {
type: DataTypes.STRING,
defaultValue: 'lev'
}
}, {
classMethods: {
associate: function (models) {
User.hasMany(models.Income, {
foreignKey: 'userId',
});
User.hasMany(models.Expense, {
foreignKey: 'userId',
});
}
}
});
const Expense = sequelize.define('Expense', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: DataTypes.INTEGER
},
value: {
allowNull: false,
type: DataTypes.FLOAT
},
text: {
type: DataTypes.STRING
},
expenseCategoryId: {
allowNull: false,
type: DataTypes.INTEGER
},
userId: {
allowNull: false,
type: DataTypes.INTEGER
}
}, {
classMethods: {
associate: function (models) {
Expense.belongsTo(models.User, {
foreignKey: 'userId'
});
Expense.belongsTo(models.ExpenseCateogory, {
foreignKey: 'expenseCateogoryId',
});
}
}
});
const ExpenseCategory = sequelize.define('ExpenseCategory', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: DataTypes.INTEGER
},
category: {
allowNull: false,
type: DataTypes.STRING
}
}, {
classMethods: {
associate: function (models) {
ExpenseCateogory.hasMany(models.Expense, {
foreignKey: 'expenseCategoryId'
});
}
}
});
I got an working answer. In this example i have a scheme where a department can have a lot of positions. The Position will include the department and the department will include its positions.
models/Department.js
module.exports = (sequelize, DataTypes) =>
{
const Sequelize = require('sequelize');
const Department = sequelize.define('Department',
{
...
}
Department.associate = function(models) {
Department.hasMany(models.Position, {
foreignKey: 'department_id',
as: 'positions'
});
};
return Department;
};
models/Position.js
module.exports = (sequelize, DataTypes) =>
{
const Sequelize = require('sequelize');
const Position = sequelize.define('Position',
{
...
}
Position.associate = function(models) {
Position.belongsTo(models.Department, {
foreignKey: 'department_id',
as: 'department',
onDelete: 'CASCADE'
});
};
return Position;
};
controllers/departmentController.js
exports.all = async function(req, res)
{
return Department
.findAll({include: [ 'positions' ]})
.then((data) => {
if (!data) { return res.status(400).json({status: 400,message: 'Registro não encontrado', data: data }); }
return res.status(200).json(data);
})
.catch((error) => {
return res.status(400).json({message: 'Falha no banco de dados.', data: error})
});
};
controllers/positionController.js
exports.all = async function(req, res)
{
return Position
.findAll({include: [ 'department' ]})
.then((data) => {
if (!data) { return res.status(400).json({status: 400,message: 'Registro não encontrado', data: data }); }
return res.status(200).json(data);
})
.catch((error) => {
console.log(error);
return res.status(400).json({message: 'Falha no banco de dados.', data: error})
});
};
Just change this sections
classMethods: {
associate: function (models) {
ExpenseCateogory.hasMany(models.Expense, {
foreignKey: 'expenseCategoryId'
});
}
}
to
ExpenseCategory.associate = (models) => {
ExpenseCategory.hasMany(models.style,{
as:'expensecategories'
});
}
so the model in full will follow this structure and the other models as well
const ExpenseCategory = sequelize.define('ExpenseCategory', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: DataTypes.INTEGER
},
category: {
allowNull: false,
type: DataTypes.STRING
}
});
ExpenseCategory.associate = (models) => {
ExpenseCategory.hasMany(models.style,{
as:'expensecategories'
});
}
return ExpenseCategory;
This is with reference to this youtube video https://www.youtube.com/watch?v=SaVxJrTRkrI and this example from github for sequelize examples on associations for models https://github.com/sequelize/express-example/tree/master/models