Reputation: 2709
In my Node API, I'm using the ORM Sequuilize and trying to understand how to make the migration file in this way to tables is referred to as each other by a foreign key.
I have a Student who HasMany Projects and Projects BelongTo one student.
So my models are like this:
module.exports = (sequelize, DataTypes) => {
const Student = sequelize.define("Student", {
_id: {
primaryKey: true,
type: DataTypes.UUID,
defaultValue: DataTypes.UUIDV4,
//autoIncrement: true
},
name: {
type: DataTypes.STRING,
allowNull: false
},
email: {
type: DataTypes.TEXT,
allowNull: false,
unique: true
},
dateOfBirth: {
type: DataTypes.DATEONLY,
allowNull: false
},
createdAt: {
type: DataTypes.DATE,
allowNull: false
},
updatedAt: {
type: DataTypes.DATE,
allowNull: false
}
});
Student.associate = function(models) {
Student.hasMany(models.Project, {
foreignKey: 'student_id',
as: 'projects',
onDelete: 'CASCADE',
});
};
return Student;
};
Project model:
module.exports = (sequelize, DataTypes) => {
const Project = sequelize.define("Project", {
project_id: {
primaryKey: true,
type: DataTypes.UUID,
defaultValue: DataTypes.UUIDV4,
//autoIncrement: true
},
student_id: {
type: DataTypes.UUIDV4,
allowNull: false,
},
name: {
type: DataTypes.STRING,
allowNull: false,
unique: true
},
description: {
type: DataTypes.TEXT,
allowNull: true
},
creationDate: {
type: DataTypes.DATEONLY,
allowNull: true
},
repoUrl: {
type: DataTypes.TEXT,
allowNull: true
},
liveUrl: {
type: DataTypes.TEXT,
allowNull: true
},
createdAt: {
type: DataTypes.DATE,
allowNull: false
},
updatedAt: {
type: DataTypes.DATE,
allowNull: false
}
});
Student.associate = function(models) {
Project.belongsTo(models.Student, {
foreignKey: "student_id",
as: "student",
onDelete: "CASCADE"
});
};
return Student;
};
My migration as follows but as I stated before I don't know how to include the foreign key and the way I did does not work, the migration is created but in the DB the relationship is not made:
Student migration
"use strict";
module.exports = {
up: (queryInterface, Sequelize) => {
return queryInterface.createTable("Students", {
_id: {
primaryKey: true,
type: Sequelize.UUID,
defaultValue: Sequelize.UUIDV4,
//autoIncrement: true
},
name: {
type: Sequelize.STRING,
allowNull: false
},
email: {
type: Sequelize.TEXT,
allowNull: false,
unique: true
},
dateOfBirth: {
type: Sequelize.DATEONLY,
allowNull: false
},
createdAt: {
type: Sequelize.DATE,
allowNull: false
},
updatedAt: {
type: Sequelize.DATE,
allowNull: false
}
});
},
down: (queryInterface, Sequelize) => {
return queryInterface.dropTable("Students");
}
};
Project migration
"use strict";
module.exports = {
up: (queryInterface, Sequelize) => {
return queryInterface.createTable("Projects", {
project_id: {
primaryKey: true,
type: Sequelize.UUID,
defaultValue: Sequelize.UUIDV4
//autoIncrement: true
},
student_id: {
foreignKey: true,
type: Sequelize.UUID,
defaultValue: Sequelize.UUIDV4,
allowNull: false
},
name: {
type: Sequelize.STRING,
allowNull: false,
unique: true
},
description: {
type: Sequelize.TEXT,
allowNull: true
},
creationDate: {
type: Sequelize.DATEONLY,
allowNull: true
},
repoUrl: {
type: Sequelize.TEXT,
allowNull: true
},
liveUrl: {
type: Sequelize.TEXT,
allowNull: true
},
createdAt: {
type: Sequelize.DATE,
allowNull: false
},
updatedAt: {
type: Sequelize.DATE,
allowNull: false
}
});
},
down: (queryInterface, Sequelize) => {
return queryInterface.dropTable("Projects");
}
};
Upvotes: 1
Views: 5010
Reputation: 102247
Here is the migration workflow:
sequelize-cli
. Student
and Project
based on your business requirements.student_id
column to Project
table). For your case, Project
table has a student_id
column as its foreign key reference to the Student
table's _id
column.Here is the working example:
models/student.js
:
module.exports = (sequelize, DataTypes) => {
const Student = sequelize.define('Student', {
_id: {
primaryKey: true,
type: DataTypes.UUID,
defaultValue: DataTypes.UUIDV4,
},
name: {
type: DataTypes.STRING,
allowNull: false,
},
email: {
type: DataTypes.TEXT,
allowNull: false,
unique: true,
},
dateOfBirth: {
type: DataTypes.DATEONLY,
allowNull: false,
},
createdAt: {
type: DataTypes.DATE,
allowNull: false,
},
updatedAt: {
type: DataTypes.DATE,
allowNull: false,
},
});
Student.associate = function(models) {
Student.hasMany(models.Project, {
foreignKey: 'student_id',
as: 'projects',
});
};
return Student;
};
models/project.js
:
module.exports = (sequelize, DataTypes) => {
const Project = sequelize.define('Project', {
project_id: {
primaryKey: true,
type: DataTypes.UUID,
defaultValue: DataTypes.UUIDV4,
},
name: {
type: DataTypes.STRING,
allowNull: false,
unique: true,
},
description: {
type: DataTypes.TEXT,
allowNull: true,
},
creationDate: {
type: DataTypes.DATEONLY,
allowNull: true,
},
repoUrl: {
type: DataTypes.TEXT,
allowNull: true,
},
liveUrl: {
type: DataTypes.TEXT,
allowNull: true,
},
createdAt: {
type: DataTypes.DATE,
allowNull: false,
},
updatedAt: {
type: DataTypes.DATE,
allowNull: false,
},
});
Project.associate = function(models) {
Project.belongsTo(models.Student, {
foreignKey: 'student_id',
as: 'student',
onDelete: 'CASCADE',
});
};
return Project;
};
migrations/20200213113039-create-student.js
:
'use strict';
module.exports = {
up: (queryInterface, Sequelize) => {
return queryInterface.createTable('Students', {
_id: {
primaryKey: true,
type: Sequelize.UUID,
defaultValue: Sequelize.UUIDV4,
},
name: {
type: Sequelize.STRING,
allowNull: false,
},
email: {
type: Sequelize.TEXT,
allowNull: false,
unique: true,
},
dateOfBirth: {
type: Sequelize.DATEONLY,
allowNull: false,
},
createdAt: {
type: Sequelize.DATE,
allowNull: false,
},
updatedAt: {
type: Sequelize.DATE,
allowNull: false,
},
});
},
down: (queryInterface, Sequelize) => {
return queryInterface.dropTable('Students');
},
};
migrations/20200213113231-create-project.js
:
'use strict';
module.exports = {
up: (queryInterface, Sequelize) => {
return queryInterface.createTable('Projects', {
project_id: {
primaryKey: true,
type: Sequelize.UUID,
defaultValue: Sequelize.UUIDV4,
},
student_id: {
type: Sequelize.UUID,
references: {
model: {
tableName: 'Students',
},
key: '_id',
},
allowNull: false,
onDelete: 'CASCADE',
},
name: {
type: Sequelize.STRING,
allowNull: false,
unique: true,
},
description: {
type: Sequelize.TEXT,
allowNull: true,
},
creationDate: {
type: Sequelize.DATEONLY,
allowNull: true,
},
repoUrl: {
type: Sequelize.TEXT,
allowNull: true,
},
liveUrl: {
type: Sequelize.TEXT,
allowNull: true,
},
createdAt: {
type: Sequelize.DATE,
allowNull: false,
},
updatedAt: {
type: Sequelize.DATE,
allowNull: false,
},
});
},
down: (queryInterface, Sequelize) => {
return queryInterface.dropTable('Projects');
},
};
After executing the command npx sequelize-cli db:migrate
, check the table information in the database(I also created seed file to insert some demo data):
node-sequelize-examples=# select * from "Students";
_id | name | email | dateOfBirth | createdAt | updatedAt
--------------------------------------+---------------+--------------------------+-------------+-------------------------------+-------------------------------
2c6db3cb-82c7-4728-a259-23520bd760d0 | Rosalind Mohr | [email protected] | 2020-02-13 | 2020-02-13 12:39:23.508379+00 | 2020-02-13 12:39:23.508379+00
(1 row)
node-sequelize-examples=# select * from "Projects";
project_id | name | description | creationDate | repoUrl | liveUrl | createdAt | updatedAt | student_id
--------------------------------------+-------+-------------+--------------+---------+---------+-------------------------------+-------------------------------+--------------------------------------
b271060c-bd20-48f4-a8a5-65508b99cfbf | nobis | | | | | 2020-02-13 12:39:23.540054+00 | 2020-02-13 12:39:23.540054+00 | 2c6db3cb-82c7-4728-a259-23520bd760d0
(1 row)
Describe the tables:
node-sequelize-examples=# \d "Students";
Table "public.Students"
Column | Type | Modifiers
-------------+--------------------------+-----------
_id | uuid | not null
name | character varying(255) | not null
email | text | not null
dateOfBirth | date | not null
createdAt | timestamp with time zone | not null
updatedAt | timestamp with time zone | not null
Indexes:
"Students_pkey" PRIMARY KEY, btree (_id)
"Students_email_key" UNIQUE CONSTRAINT, btree (email)
Referenced by:
TABLE ""Projects"" CONSTRAINT "Projects_student_id_fkey" FOREIGN KEY (student_id) REFERENCES "Students"(_id) ON UPDATE CASCADE ON DELETE CASCADE
node-sequelize-examples=# \d "Projects";
Table "public.Projects"
Column | Type | Modifiers
--------------+--------------------------+-----------
project_id | uuid | not null
name | character varying(255) | not null
description | text |
creationDate | date |
repoUrl | text |
liveUrl | text |
createdAt | timestamp with time zone | not null
updatedAt | timestamp with time zone | not null
student_id | uuid |
Indexes:
"Projects_pkey" PRIMARY KEY, btree (project_id)
"Projects_name_key" UNIQUE CONSTRAINT, btree (name)
Foreign-key constraints:
"Projects_student_id_fkey" FOREIGN KEY (student_id) REFERENCES "Students"(_id) ON UPDATE CASCADE ON DELETE CASCADE
I believe that you want to delete all projects of a user when the user is deleted.
Upvotes: 5