I am new developer and am trying to teach myself Sequelize and mysql with some little test projects. What I have right now is a little RPG team strength analyzer. I have a SQL table of Units, which has schema (id, name, elementOne, elementTwo) - integer, string, string, string.
For now, the elementOne and ElementTwo tables are both the same 18 string values because I couldn't figure out how to set up the Sequelize query with foreign keys refs to the same table (e.g. just 'elements').
Adding to the Unit table works fine on a local server, but breaks on Heroku ONLY when trying to add a third unit with the following error:
Error was: { SequelizeForeignKeyConstraintError: Cannot add or update a child
row: a foreign key constraint fails (`heroku_f4daeab1e260595`.`units`,
CONSTRAINT `units_ibfk_1` FOREIGN KEY (`id`) REFERENCES `elementtwos` (`id`)
ON DELETE CASCADE ON UPDATE CASCADE)
Here are all the tables and the relationship declarations.
const Unit = sequelize.define('unit', {
id: {
type: Sequelize.INTEGER,
allowNull: false,
unique: true,
primaryKey: true,
autoIncrement: true
},
name: {
type: Sequelize.STRING,
allowNull: false,
unique: false
},
image: {
type: Sequelize.STRING,
allowNull: true,
unique: false
},
elementOne: {
type: Sequelize.INTEGER,
allowNull: true,
references: {
model: Element,
key: 'id'
}
},
elementTwo: {
type: Sequelize.INTEGER,
allowNull: true,
defaultValue: 10001,
references: {
model: ElementTwo,
key: 'id'
}
}
});
const Element = sequelize.define('element', {
id: {
type: Sequelize.INTEGER,
allowNull: false,
unique: true,
primaryKey: true,
autoIncrement: true
},
name: {
type: Sequelize.STRING,
allowNull: false,
unique: false
}
});
const ElementTwo = sequelize.define('elementtwo', {
id: {
type: Sequelize.INTEGER,
allowNull: false,
unique: true,
primaryKey: true,
autoIncrement: true
},
name: {
type: Sequelize.STRING,
allowNull: false,
unique: false
}
});
After these are all loaded, I set up the following:
Unit.belongsTo(Element, {foreignKey: 'elementOne'});
Unit.belongsTo(ElementTwo, {foreignKey: 'elementTwo'});
ElementTwo.hasMany(Unit, {foreignKey: 'id'});
Element.hasMany(Unit, {foreignKey: 'id'});
And this is the query that Sequelize is doing (in a Unit.create({...}):
INSERT INTO `units`
(`id`,`name`,`image`,`elementOne`,`elementTwo`,`createdAt`,`updatedAt`) VALUES
(DEFAULT,'raichu','http://longimgurl.png',13,10001,'2017-06-14
12:57:54','2017-06-14 12:57:54');
If anyone can offer any advice it would be greatly appreciated.
this is mysql error and because you define foreign key constraint on you table and try to insert unavailable value in fk field that does not exit in target table,
check element and elementTwo table and make sure this values are available
Related
UPDATE
someone below suggested adding in a model id for shoutouts and I'm no longer getting the error, but now nothing is being saved to my database?
adding in the new information below:
I have a one to many relationship between users and shoutouts. Both models have email property,
I am trying to use a magic method to setup the shoutout. When I use user.createShoutout()
I can generate the shoutout, but the email property doesn't show up in the database.
const Sequelize = require('sequelize')
const db = require('../db')
const Shoutout = db.define('shoutout', {
//NEW
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER
}, //OLD
name: {
type: Sequelize.STRING,
validate: {
notEmpty: true
},
email: {
type: Sequelize.STRING,
unique: true,
allowNull: false
}
},
message: {
type: Sequelize.TEXT,
allowNull: false
},
from: {
type: Sequelize.STRING
}
})
module.exports = Shoutout
associations:
User.hasMany(Shoutouts)
Shoutouts.belongsTo(User)
User.hasMany(Emails)
Emails.belongsTo(User)
when I use user.AddShoutout()
as follows:
let paramsObj = {
name: addEmail.firstName,
email:addEmail.email,
message: 'test msg',
userId: 3
}
//NEW
let id = 1;
const addInfo = await userThree.addShoutout(id,paramsObj)
//NEW
not getting the object error anymore, in fact not seeing any errors. But when I look in my shoutouts table nothing is getting added.
when I console.log addInfo
The user who tried to create the shoutout gets returned?
I need help with trying to get this user model magic method to generate a new shoutout!
Thanks for reading this, and any advice!
Your email field is nested within name field
const Sequelize = require('sequelize')
const db = require('../db')
const Shoutout = db.define('shoutout', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER
}, //OLD
name: {
type: Sequelize.STRING,
validate: {
notEmpty: true
},
email: { # <----------------------------- nested too deep
type: Sequelize.STRING,
unique: true,
allowNull: false
}
},
message: {
type: Sequelize.TEXT,
allowNull: false
},
from: {
type: Sequelize.STRING
}
})
module.exports = Shoutout
I've created a database with two tables, Users and Points. A user can have many points and a point stores the ID of the user who sent it and the user who received it. I am trying to query for a table grouped by user showing the sum of the amounts of all their points, which is working querying raw in postgresql but not in sequelize.
Working in postgresql:
Creating the models with sequelize:
User.init(
{
id: {
type: DataTypes.INTEGER,
autoIncrement: true,
primaryKey: true,
},
telegram_id: {
type: DataTypes.INTEGER,
allowNull: false,
unique: true,
},
name: {
type: DataTypes.STRING,
allowNull: false,
},
},
{
tableName: "users",
sequelize: sequelize, // this bit is important
}
);
Point.init(
{
id: {
type: DataTypes.INTEGER,
autoIncrement: true,
primaryKey: true,
},
amount: {
type: DataTypes.INTEGER,
allowNull: false,
},
to_id: {
type: DataTypes.INTEGER,
allowNull: false,
},
from_id: {
type: DataTypes.INTEGER,
allowNull: false,
},
},
{
tableName: "points",
sequelize: sequelize, // this bit is important
}
);
User.hasMany(Point, {
sourceKey: "telegram_id",
foreignKey: "to_id",
as: "recievedPoints", // this determines the name in `associations`!
});
User.hasMany(Point, {
sourceKey: "telegram_id",
foreignKey: "from_id",
as: "sentPoints", // this determines the name in `associations`!
});
Point.belongsTo(User, {
foreignKey: "to_id",
targetKey: "telegram_id",
as: "toUser",
});
Point.belongsTo(User, {
foreignKey: "from_id",
targetKey: "telegram_id",
as: "fromUser",
});
Attempting to make same query with sequelize:
const points = await Point.findAll({
attributes: [
"users.name",
"points.to_id",
[Sequelize.fn("SUM", Sequelize.col("points.amount")), "points.amount"],
],
include: ["toUser"],
group: ["users.name", "points.to_id"],
});
Resulting error:
SequelizeDatabaseError: invalid reference to FROM-clause entry for table "users"
SQL generated by sequelize:
SELECT "users"."name", "points"."to_id", SUM("points"."amount") AS "points.amount", "toUser"."id" AS "toUser.id", "toUser"."telegram_id" AS "toUser.telegram_id", "toUser"."name" AS "toUser.name", "toUser"."createdAt" AS "toUser.createdAt", "toUser"."updatedAt" AS "toUser.updatedAt" FROM "points" AS "Point"
LEFT OUTER JOIN "users" AS "toUser" ON "Point"."to_id" = "toUser"."telegram_id" GROUP BY "users"."name", "points"."to_id";
RAW QUERY :
SELECT "users"."name", "points"."to_id", SUM("points"."amount") AS "points.amount", "toUser"."id" AS "toUser.id", "toUser"."telegram_id" AS "toUser.telegram_id", "toUser"."name" AS "toUser.name", "toUser"."createdAt" AS "toUser.createdAt", "toUser"."updatedAt" AS "toUser.updatedAt"
FROM "points" AS "Point"
LEFT OUTER JOIN "users" AS "toUser" ON "Point"."to_id" = "toUser"."telegram_id" GROUP BY "users"."name", "points"."to_id";
As per your raw query :
Change "users" to "toUser" every where
Change "points" to "Point" every where , like this :
const points = await Point.findAll({
attributes: [
"toUser.name",
"Point.to_id",
[Sequelize.fn("SUM", Sequelize.col("Point.amount")), "Point.amount"],
],
include: ["toUser"],
group: ["toUser.name", "Point.to_id"],
});
I am using Sequelize to create the db schema. And I cannot find how to set the foreign key name in a many to many relationship.
I have a investment_manager table
const Investment_manager = sequelize.define('investment_manager', {
im_id : {type: Sequelize.INTEGER, allowNull: false, primaryKey: true, autoIncrement: true},
im_name : {type: Sequelize.STRING, allowNull: false}
// Other fields ....
});
a project table
const Project = sequelize.define('project', {
project_id : {type: Sequelize.INTEGER, allowNull: false, primaryKey: true, autoIncrement: true},
project_name : {type: Sequelize.STRING, allowNull: false},
// Other fields ....
});
a asso_project_im table
const Asso_project_im = sequelize.define('asso_project_im', {
asso_id: {type: Sequelize.INTEGER, allowNull: false, primaryKey: true, autoIncrement: true},
// Other fields ....
});
I connection the tables using belongsToMany
investment_manager.belongsToMany(project, {as: 'im', through: 'asso_project_im', foreign_key: 'im_id'});
project.belongsToMany(investment_manager, {as: 'project', through: 'asso_project_im', foreign_key: 'project_id'});
I want to create foreign key in Asso_project_im table named 'im_id' and 'project_id', is there any way to do that? Thank you a lot!
I am using sequelize to define my Model with postgres.
I have the following
#Options({
sequelize: db.main,
freezeTableName: true,
paranoid: true,
tableName: 'artist',
timestamps: true,
indexes: [{
unique: true,
fields: ['name'],
}],
})
#Attributes({
id: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true,
},
name: {
type: DataTypes.TEXT,
allowNull: false,
},
My Q is how do I get a custom error message when I try to create an artist with the same name as in DB. As per http://docs.sequelizejs.com/manual/tutorial/models-definition.html#validations
I mean I can use
validate: {
isIn: [['foo', 'bar']],
msg: 'Validation error for Artists w.r.t length',
}
But I cant seem to get a custom error message for Index on Model.
It throws generic error message lower(name) must be unique
How do I add custom error message for sequelize Index
"same name" means the unique index?
name: {
type: DataTypes.TEXT,
allowNull: false,
unique: {
msg: 'Validation error for Artists w.r.t length',
}
}
So I have two tables: Class and Course. Each Class has a course_id that defines what type of course it is on the Course table. Here are my models:
const Class = sequelize.define('class', {
class_date: Sequelize.DATE,
begin_time: Sequelize.TIME,
end_time: Sequelize.TIME,
max_capacity: Sequelize.INTEGER,
is_published: Sequelize.BOOLEAN,
training_facility_id: Sequelize.INTEGER,
state_id: Sequelize.INTEGER,
registration_deadline: Sequelize.DATE,
course_id: Sequelize.INTEGER,
is_report_60_generated: Sequelize.BOOLEAN,
completed_by_user_id: Sequelize.INTEGER
}, {
timestamps: false,
freezeTableName: true
})
const Course = sequelize.define('course', {
code: Sequelize.STRING,
name: Sequelize.STRING
}, {
timestamps: false,
freezeTableName: true
})
When I hit the classes endpoint, I get a array of classes. How would I set up the query to respond with the course name and code for each class instead of just the course_id?
You will need to create a relationship between the Class and Course models. If you specify the underscored: true option in the Model definition it won't use camel case and will automatically create the Class.course_id column, so you don't need to define it (the same probably goes for completed_by_user_id).
const Class = sequelize.define('class', {
class_date: Sequelize.DATE,
begin_time: Sequelize.TIME,
end_time: Sequelize.TIME,
max_capacity: Sequelize.INTEGER,
is_published: Sequelize.BOOLEAN,
training_facility_id: Sequelize.INTEGER,
state_id: Sequelize.INTEGER,
registration_deadline: Sequelize.DATE,
// this will be auto-created by the relationship
// course_id: Sequelize.INTEGER,
is_report_60_generated: Sequelize.BOOLEAN,
// you probably want a relationship here as well
completed_by_user_id: Sequelize.INTEGER
}, {
timestamps: false,
freezeTableName: true,
// use underscored names
underscored: true,
})
const Course = sequelize.define('course', {
code: Sequelize.STRING,
name: Sequelize.STRING
}, {
timestamps: false,
freezeTableName: true,
underscored: true,
})
Based on your data model it seems as though each Class will require an associated Course with different attributes like start time, etc, so you will tell Sequelize that each Class belongsTo() a Course.
// tell Sequelize that once course will be assigned to many classes, and it is required (not null)
Class.belongsTo(Course, { foreignKey: { allowNull: false } })
Once they are related you can use the include option value to specify a model to join to your primary query. If you use as in the relationship you must specify it here as well.
// do a joined query using "include"
Class.findAll({
include: [
{
model: Course
}
]
})