Sequelize addConstraint syntax - node.js

Im trying to add two tables, Playlist and Label.
Label optionally has a playlist, many playlists can relate to the same label.
In order to add the foreign key constraint to playlist im trying to add it using addConstraint.
The docs are terrible on this .
This is what i have:
"use strict";
module.exports = {
up: async (queryInterface, Sequelize) => {
await queryInterface.createTable("Playlist", {
id: { type: Sequelize.STRING, primaryKey: true, allowNull: false },
track_uri: Sequelize.STRING,
track: Sequelize.STRING(150),
artist: Sequelize.STRING(150),
added_at: {
type: Sequelize.DATE,
defaultValue: new Date(),
allowNull: false,
},
created_at: {
type: Sequelize.DATE,
defaultValue: new Date(),
allowNull: false,
},
is_album_track: Sequelize.BOOLEAN,
label: { type: Sequelize.STRING, unique: true },
});
await queryInterface.createTable("Label", {
id: { type: Sequelize.STRING, primaryKey: true },
playlist_link: {
type: Sequelize.STRING(150),
unique: true,
allowNull: false,
},
password: { type: Sequelize.STRING, allowNull: false },
email: { type: Sequelize.STRING, allowNull: false },
playlist: {
type: Sequelize.STRING,
foreignKey: true,
references: {
model: "Playlist",
label: "id",
},
},
});
await queryInterface.addConstraint("Playlist", {
type: "foreign key",
fields: ["label"],
name: "label_fkey",
references: {
table: "Label",
field: "id",
},
onDelete: "cascade",
onUpdate: "cascade",
});
},
down: async (queryInterface, Sequelize) => {
await queryInterface.dropTable("Label");
await queryInterface.dropTable("Playlist");
},
};
Im getting this error:
ERROR: column "label" referenced in foreign key constraint does not exist

Related

Sequelize foreign key with association

I have a database that was created with Postgres that was set up for a single foreign key association, Now, this would be mapped as a role table model
consider I have two tables user and roles
roles contain role details and user contain user details of role
const uuid = require('uuid/v4');
('use strict');
module.exports = (sequelize, DataTypes) => {
const role = sequelize.define(
'role',
{
id: {
allowNull: false,
primaryKey: true,
type: DataTypes.UUID,
},
name: {
type: DataTypes.STRING,
allowNull: false,
},
},
{}
);
role.beforeCreate((role) => (role.id = uuid()));
role.associate = function (models) {
role.hasMany(models.user), { foreignKey: 'roleId', as: 'user_roleId' };
};
return role;
};
role migration
'use strict';
module.exports = {
up: (queryInterface, Sequelize) => {
return queryInterface.createTable('roles', {
id: {
allowNull: false,
primaryKey: true,
type: Sequelize.UUID,
},
name: {
type: Sequelize.STRING,
},
createdAt: {
allowNull: false,
type: Sequelize.DATE,
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE,
},
});
},
down: (queryInterface, Sequelize) => {
return queryInterface.dropTable('roles');
},
};
user model
const uuid = require('uuid/v4');
('use strict');
module.exports = (sequelize, DataTypes) => {
const user = sequelize.define(
'user',
{
id: {
allowNull: false,
primaryKey: true,
type: DataTypes.UUID,
},
firstName: {
type: DataTypes.STRING,
allowNull: false,
},
lastName: DataTypes.STRING,
email: {
type: DataTypes.STRING,
allowNull: false,
},
password: {
type: DataTypes.STRING,
allowNull: false,
},
phoneNumber: {
type: DataTypes.STRING,
},
roleId: {
type: DataTypes.UUID,
},
},
{
timestamps: true,
paranoid: true,
defaultScope: {
attributes: { exclude: ['password'] },
},
}
);
user.beforeCreate((user) => (user.id = uuid()));
user.associate = function (models) {
user.belongsTo(models.role, { foreignKey: 'roleId', onDelete: 'CASCADE' });
};
return user;
};
user migration
'use strict';
module.exports = {
up: (queryInterface, Sequelize) => {
return queryInterface.createTable('users', {
id: {
allowNull: false,
primaryKey: true,
type: Sequelize.UUID,
},
firstName: {
type: Sequelize.STRING,
},
lastName: {
type: Sequelize.STRING,
},
email: {
type: Sequelize.STRING,
},
password: {
type: Sequelize.STRING,
},
phoneNumber: {
type: Sequelize.STRING,
},
roleId: {
type: Sequelize.UUID,
},
createdAt: {
allowNull: false,
type: Sequelize.DATE,
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE,
},
deletedAt: {
allowNull: true,
type: Sequelize.DATE,
},
});
},
down: (queryInterface, Sequelize) => {
return queryInterface.dropTable('users');
},
};
after running the migration these tables are created in my database.role_id is also present in the user table. but role_id is not generated as a foreign key in my user table. also please verify that the relationship which is mention here(one to many) is correct or not.
please verify my code and give me any suggestions if any changes required. I'm new in development
Your user migration also needs to know about the foreign key; you do this by adding a references: key to the column definition. The Sequelize documentation has a foreign key example; scroll about half way down the page (or just search for references).
In your case the user migration should look something like:
module.exports = {
up: (queryInterface, Sequelize) => {
return queryInterface.createTable('users', {
// ... other fields omitted
roleId: {
type: Sequelize.UUID,
references: {
model: { tableName: 'role' }
key: 'id',
},
},
// ... more fields omitted
});
},
// down: omitted
}

filter Sequelize belongsToMany

I have the following problem:
I defined my tables (product and collection) like this:
module.exports = (sequelize, type) => {
return sequelize.define('product', {
id: {
type: type.UUID,
primaryKey: true,
defaultValue: type.UUIDV4,
},
title: {
type: type.STRING,
allowNull: false,
},
description: {
type: type.TEXT,
allowNull: false,
},
width: {
type: type.FLOAT,
allowNull: false,
},
height: {
type: type.FLOAT,
allowNull: false,
},
weight: {
type: type.FLOAT,
allowNull: false,
},
length: {
type: type.FLOAT,
allowNull: false,
},
vendor: {
type: type.STRING,
allowNull: false,
},
status: {
type: type.ENUM,
values: ['inactive', 'active'],
defaultValue: 'active',
allowNull: false,
},
})
}
module.exports = (sequelize, type) => {
return sequelize.define('collection', {
id: {
type: type.UUID,
primaryKey: true,
defaultValue: type.UUIDV4,
},
name: {
type: type.STRING,
allowNull: false,
},
image: {
type: type.STRING,
allowNull: true,
},
createdAt: {
type: type.DATE,
allowNull: false,
},
updatedAt: {
type: type.DATE,
allowNull: false,
},
status: {
type: type.ENUM,
values: ['inactive', 'active'],
defaultValue: 'active',
allowNull: false,
},
})
}
Then, I need associated the tables (product and collection) with belongsToMany association and i did it like this:
const ProductModel = require('../api/product/model')
const CategoryModel = require('../api/category/model')
const Product = ProductModel(sequelize, Sequelize)
const Collection = CollectionModel(sequelize, Sequelize)
Product.belongsToMany(Collection, {
through: ProductCollection,
foreignKey: 'productId',
otherKey: 'collectionId',
unique: false,
})
Collection.belongsToMany(Product, {
through: ProductCollection,
foreignKey: 'collectionId',
otherKey: 'productId',
unique: false,
})
Now, i want to get all the products of a collection given by the id sent from the body of the request, i have little time working with sequelize and i donĀ“t know how to do this kind of query.
Can you help me with that?
you can use something like this
let products = Collection.findAll({
where: {
id: collection.id,
},
attributes: ['id', 'name'],
include: [{
model: Product,
through: {
model: ProductCollection,
},
as: 'products',
attributes: ['id', 'title', 'description']
}],
});
return products
hope it helps

Sequelize hasMany assocaition

I am considering these 2 tables "exam_response" and "answer" for hasMany association.
Where both the tables contains "question_id". Using question_id I need the answers.
exam_response table
module.exports = (sequelize, DataTypes) => {
const exam_response = sequelize.define('exam_response', {
id: {
allowNull: false,
primaryKey: true,
type: DataTypes.UUID,
defaultValue: DataTypes.UUIDV4
},
session_id: {
type: DataTypes.UUID,
allowNull: false
},
exam_id: {
type: DataTypes.UUID,
allowNull: false
},
user_id: {
type: DataTypes.UUID,
allowNull: false
},
question_id: {
type: DataTypes.UUID,
allowNull: false
},
answer_ids: {
type: DataTypes.ARRAY(DataTypes.UUID),
allowNull: false
},
is_correct: {
type: DataTypes.BOOLEAN,
allowNull: false
},
is_bookmarked: {
type: DataTypes.BOOLEAN,
allowNull: false
},
is_attempted: {
type: DataTypes.BOOLEAN,
allowNull: false
},
createdAt: {
type: DataTypes.DATE,
field: 'created_at'
},
updatedAt: {
type: DataTypes.DATE,
field: 'updated_at'
}
}, {});
exam_response.associate = function (models) {
// associations can be defined here
exam_response.hasMany(models.answer, {
foreignKey: 'question_id', sourceKey: 'question_id',as:'exam_answers'
});
};
answer table
'use strict';
module.exports = (sequelize, DataTypes) => {
const answer = sequelize.define('answer', {
//{
// "id":"",
// "question_id":"123",
// "position":0,
// "answer":"This is answer 1."
// }
id: {
allowNull: false,
primaryKey: true,
type: DataTypes.UUID,
defaultValue: DataTypes.UUIDV4
},
question_id: {
allowNull: false,
type: DataTypes.UUID
},
position: {
allowNull: false,
type: DataTypes.INTEGER
},
answer: {
allowNull: false,
type: DataTypes.TEXT
},
publish_status: {
allowNull: false,
type: DataTypes.ENUM('published', 'unpublished', 'deleted')
},
language: {
type: DataTypes.ENUM('en', 'kn', 'hi')
},
createdAt: {
type: DataTypes.DATE,
field: 'created_at'
},
updatedAt: {
type: DataTypes.DATE,
field: 'updated_at'
}
}, {});
answer.associate = models => {
answer.belongsTo(models.question,{foreignKey:'question_id',as:'answers'});
answer.belongsTo(models.exam_response,{foreignKey:'question_id', targetKey: 'question_id',as:'exam_answers'});
};
return answer;
};
Query::
ExamResponse.findAll({
where: {
exam_id
},
include: [
{
model: Answer,as:'exam_answers'
}
],
}).then(resp => {
response.successGet(res, resp, 'Exam Response');
}).catch(next)
I am getting the output but associated part("exam_answers") is empty.
If I use raw query, i am able to get the output. But the Query is only fetching me the exam_response not the answer even though the value exists.

sequelize - inner join gives an error after added a foreign key

i have these 2 models:
module.exports = function(sequelize, DataTypes) {
return sequelize.define('services_prices', {
id: {
type: DataTypes.INTEGER(11),
allowNull: false,
primaryKey: true
},
service_id: {
type: DataTypes.INTEGER(11),
allowNull: true,
references: {
model: 'services',
key: 'id'
}
},
created_at: {
type: DataTypes.DATE,
allowNull: false
},
limit: {
type: DataTypes.INTEGER(11),
allowNull: true
},
price: {
type: DataTypes.INTEGER(11),
allowNull: true
}
});
};
which is parent of this model: (services_user_prices can override services_prices )
module.exports = function(sequelize, DataTypes) {
return sequelize.define('services_user_prices', {
id: {
type: DataTypes.INTEGER(11),
allowNull: false,
primaryKey: true,
autoIncrement: true
},
user_id: {
type: DataTypes.INTEGER(11),
allowNull: true
},
created_at: {
type: DataTypes.DATE,
allowNull: false
},
currency: {
type: DataTypes.STRING(255),
allowNull: true
},
is_active: {
type: DataTypes.INTEGER(1),
allowNull: true,
defaultValue: '0'
},
is_trial: {
type: DataTypes.INTEGER(1),
allowNull: true,
defaultValue: '0'
},
start_date: {
type: DataTypes.DATE,
allowNull: false
},
end_date: {
type: DataTypes.DATE,
allowNull: true
},
price: {
type: DataTypes.INTEGER(11),
allowNull: true
},
bundle_price_id: {
type: DataTypes.INTEGER(11),
allowNull: true,
references: {
model: 'services_prices',
key: 'id'
}
}
});
};
when trying to join them i get an error:
EagerLoadingError: services_prices is not associated to services_user_prices!
const result= await db.services_user_prices.findOne({
where: { is_active: 1, user_id: 123 }, include:[{db.services_prices}]
});
in the db services_user_prices has foreign key to services_prices table
what am i doing wrong?
Well if you are using sequelize then you need to update your model because
by default, sequelize will be looking for foreign key starts with model name like
you have defined bundle_price_id as a foreign key for services_prices.
You need to change your column name to services_price_id then it will get fixed.
or if you want to use bundle_price_id you need to define it in your model relation as.
Model.belongsTo(models.ModelName, { foreignKey: 'your_key'} )
Please feel free if you need to ask anything else.
As complement of the above answer you need to add an identifier with as: on the association like this:
Model.belongsTo(models.ModelName, { foreignKey: 'your_key', as:'your_identifier' } )
Then when you do the include on the method you also call the identifier:
await db.services_user_prices.findOne({
where: { is_active: 1, user_id: 123 },
include:[{
model: db.services_prices
as: 'your_identifier'
}]
});
If you don't define the foreignKey field, the as field will set the column name.

Sequelize query singular instead of plural table name

I have an problem and I can't find anything that can solve it. I'm using sequelize and graphql to create an API in nodeJS. The database is using PostgresQL.
So I have two models: Simulation and Data. They are in two tables Simulations and Datas. The relation between them is one Simulation to many Datas.
The problem is this: when I make a query with Simulation (ex: Simulation.findAll()), it works correctly, querying "Simulations", but with Data, it queries on the "Data" table, not "Datas". What I really don't understand is that the code of my two models are almost the same.
Here is the model for Simulation:
module.exports = (sequelize, DataTypes) => {
const Simulation = sequelize.define('Simulation', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: DataTypes.INTEGER,
},
name: {
type: DataTypes.STRING,
allowNull: false,
},
});
Simulation.associate = function(models) {
Simulation.hasMany(models.Data, {
foreignKey: 'SimulationId',
})
};
return Simulation;
};
Here is the model for Data:
module.exports = (sequelize, DataTypes) => {
const Data = sequelize.define('Data', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: DataTypes.INTEGER,
},
name: {
type: DataTypes.STRING,
allowNull: false
},
content: {
type: DataTypes.TEXT,
allowNull: false
},
SimulationId: {
allowNull: false,
type: DataTypes.INTEGER,
},
});
Data.associate = function(models) {
Data.belongsTo(models.Simulation, {
foreignKey: 'SimulationId',
targetKey: 'id',
allowNull: false,
onDelete: 'CASCADE'
});
};
return Data;
};
And here are the migration files:
Simulation
'use strict';
module.exports = {
up: (queryInterface, Sequelize) => {
return queryInterface.createTable('Simulations', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER
},
name: {
type: Sequelize.STRING,
allowNull: false,
},
createdAt: {
allowNull: false,
type: Sequelize.DATE
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE
}
});
},
down: (queryInterface, Sequelize) => {
return queryInterface.dropTable('Simulations');
}
};
Data
'use strict';
module.exports = {
up: (queryInterface, Sequelize) => {
return queryInterface.createTable('Datas', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER
},
name: {
type: Sequelize.STRING,
allowNull: false
},
content: {
type: Sequelize.TEXT,
allowNull: false
},
SimulationId: {
allowNull: false,
type: Sequelize.INTEGER,
onDelete: 'CASCADE',
references: {
model: 'Simulation',
key: 'id',
as: 'SimulationId',
},
},
createdAt: {
allowNull: false,
type: Sequelize.DATE
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE
}
});
},
down: (queryInterface, Sequelize) => {
return queryInterface.dropTable('Datas');
}
};
Thanks for helping me :)
You can use freezeTableName option to set whatever the model name you want, sequelize will not make the model names plural.
Sequelize automatically makes the model names plural. Why not call the table "Data" It is actually a plural form of the word "Data", so maybe a better name for the table.

Resources