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
Related
My models:
'use strict';
module.exports = (sequelize, DataTypes) => {
const Vendor = sequelize.define('Vendor', {
id: { type: DataTypes.INTEGER, allowNull: false, autoIncrement: true, primaryKey: true },
// other fields
}, {});
Vendor.associate = function (models) {
Vendor.belongsToMany(models.Corporate, { through: 'VendorCorporates', foreignKey: 'vendorId' });
};
return Vendor;
};
and
'use strict';
module.exports = (sequelize, DataTypes) => {
const Corporate = sequelize.define('Corporate', {
id: { type: DataTypes.INTEGER, allowNull: false, autoIncrement: true, primaryKey: true },
// other fields
}, {});
Corporate.associate = function (models) {
Corporate.belongsToMany(models.Vendor, { through: 'VendorCorporates', foreignKey: 'corporateId' });
};
return Corporate;
};
and the migration for the association (link) table:
'use strict';
const vendorCorps = 'VendorCorporates', vendorId = 'vendorId', corpId = 'corporateId';
module.exports = {
up: (queryInterface, Sequelize) => {
return queryInterface.createTable(vendorCorps, {
vendorId: {
type: Sequelize.INTEGER,
references: {
model: 'Vendors',
key: 'id'
},
onUpdate: 'CASCADE',
onDelete: 'CASCADE'
},
corporateId: {
type: Sequelize.INTEGER,
references: {
model: 'Corporates',
key: 'id'
},
onUpdate: 'CASCADE',
onDelete: 'CASCADE'
},
// notice no timestamps
});
},
down: (queryInterface, Sequelize) => {
return queryInterface.dropTable('VendorCorporates');
}
};
Now when I try to get the Corporates that are associated with a Vendor:
let vendor = await models.Vendor.findByPk(pk);
let corporates = await vendor.getCorporates();
the query fails because sequelize generates SQL with the fields updatedAt and createdAt. How do I tell sequelize to generate SQL without the timestamp fields?
Clarification: I want timestamps in the Corporate & Vendor models, but none in the link/association table, and I want the join query (vendor.getCorporates()) to be generated accordingly.
You can indicate this using the timestamps option. For instance:
const Corporate = sequelize.define('Corporate', {
id: { type: DataTypes.INTEGER, allowNull: false, autoIncrement: true, primaryKey: true },
// other fields
}, {
timestamps: false
});
Finally solved this by writing a model for the n:m association itself:
'use strict';
module.exports = (sequelize, DataTypes) => {
const VendorCorporate = sequelize.define('VendorCorporate', {
vendorId: DataTypes.INTEGER,
corporateId: DataTypes.INTEGER
}, { timestamps: false });
VendorCorporate.associate = function (models) {
// associations can be defined here
};
return VendorCorporate;
};
and changing:
// db/models/vendor.js
Vendor.belongsToMany(models.Corporate, { through: 'VendorCorporates', foreignKey: 'vendorId' });
to:
Vendor.belongsToMany(models.Corporate, { through: models.VendorCorporate, foreignKey: 'vendorId' });
and making a similar change in the Corporate model file.
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');
}
};
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 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
I am trying to do Eager Loading in Sequelize with PostgreSQL where I need to find the Users which have a given specific Mail id or basically, i am performing find operation on Mail model while using include to include User model
UserModel :
module.exports = function (sequelize, Sequelize) {
var User = sequelize.define('User', {
userId: {
type: Sequelize.INTEGER,
primaryKey: true,
autoIncrement: true
},
firstname: {
type: Sequelize.STRING,
require: true
},
lastname: {
type: Sequelize.STRING,
require: true
},
age: {
type: Sequelize.INTEGER,
require: true
},
phone: {
type: Sequelize.STRING,
require: true
},
location: {
type: Sequelize.STRING,
require: true
},
createdAt: {
type: Sequelize.DATE,
defaultValue: Sequelize.NOW
},
updatedAt: {
type: Sequelize.DATE,
defaultValue: Sequelize.NOW
}
});
return User;
};
MailModel :
module.exports = function (sequelize, Sequelize) {
var User = require('./User.js')(sequelize, Sequelize)
var Mail = sequelize.define('Mail', {
name: {
type: Sequelize.STRING,
require: true
}
});
Mail.belongsTo(User);
return Mail;
};
MailController :
var db = require('../services/db.js');
module.exports = {
create: function (req, res, next) {
var Mailm = db.MailModel;
var name = req.body;
try {
db.sequelize.sync().then(function () {
Mailm.create(name).then(function (found) {
return res.json({
success: true,
message: found.get({
plain: true
})
});
})
});
} catch (ex) {
res.json({
success: false,
exception: ex
});
return;
}
},
query: function (req, res, next) {
var Mailm = db.MailModel;
var Userm = db.UserModel;
var name = req.body;
var option = {};
option.where = name;
option.include = [{
model: Userm
}];
try {
Mailm.findAll(option).then(function (found) {
console.log(found);
return res.json({
success: true,
message: found
});
});
} catch (ex) {
res.json({
success: false,
exception: ex
});
return;
}
}
};
It is returning me the records of both User and Mail table in exactly the right way .
Output :
{
"success": true,
"message":[
{
"id": 2,
"name": "Mailb2",
"createdAt": "2015-07-30T07:32:51.807Z",
"updatedAt": "2015-07-30T07:32:51.807Z",
"UserUserId": 2,
"User":{
"userId": 2,
"firstname": "Prerna",
"lastname": "Jain",
"age": 20,
"phone": "9812123456",
"location": "Sirsa",
"createdAt": "2015-07-30T07:30:48.000Z",
"updatedAt": "2015-07-30T07:30:48.000Z"
}
}
]
}
But I want to disable createdAt and updatedAt fields of User table so that it does not give me these two fields in the output for User.
I have tried a lot as of how to do this but still in vain.Can anyone please help me out.
I bet this is coming late, add attribute/properties to your models called timestamps, it accepts a boolean as a value. For example:
module.exports = function (sequelize, Sequelize) {
var User = require('./User.js')(sequelize, Sequelize)
var Mail = sequelize.define('Mail', {
name: {
type: Sequelize.STRING,
require: true
}
},
{
// This does the magic
timestamps: false,
});
Mail.belongsTo(User);
return Mail;
};
Also, add it to the User model:
var User = sequelize.define('User', {
userId: {
type: Sequelize.INTEGER,
primaryKey: true,
autoIncrement: true
},
firstname: {
type: Sequelize.STRING,
require: true
},
lastname: {
type: Sequelize.STRING,
require: true
},
age: {
type: Sequelize.INTEGER,
require: true
},
phone: {
type: Sequelize.STRING,
require: true
},
location: {
type: Sequelize.STRING,
require: true
},
createdAt: {
type: Sequelize.DATE,
defaultValue: Sequelize.NOW
},
updatedAt: {
type: Sequelize.DATE,
defaultValue: Sequelize.NOW
}
},
{
timestamps: false
});
return User;
};
You can use
Model.findAll({
attributes: { exclude: ['baz'] }
});
more examples with attributes - http://docs.sequelizejs.com/en/latest/docs/querying/#attributes