重新理解 Sequelize 中的 Migration 和 Model

希望真的有搞清楚了。

sequelize 的 migration

簡述

之前常常搞不清楚 Model 和 Migration 之間 的差別在哪裡,所以這邊先做個解說。

Model 歸 Model,Migation 歸 Migration,它們是獨立的兩個東西。

關於 Model

首先,Model 只是用來設定你要用 JS 操作時的資料結構,例如下面這個 Post 的 Model:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
'use strict';
const {
Model
} = require('sequelize');
module.exports = (sequelize, DataTypes) => {
class Post extends Model {
static associate(models) {
// 加了這段後才可以用「include」這個屬性
Post.belongsTo(models.Category)
}
}
// 可以對這個 Model 操作的資料結構
Post.init({
title: DataTypes.STRING,
preview: DataTypes.TEXT,
content: DataTypes.TEXT,
CategoryId: DataTypes.INTEGER,
isDeleted: DataTypes.BOOLEAN
}, {
sequelize,
modelName: 'Post',
});
return Post;
};

舉例來說,如果現在把 Model 的 title 拿掉,那麼就算你的 Table 裡面有 title 欄位,你也沒辦法用 JS 去存取,因為你沒把它定義在 Model 裡面,這就是我以前才踩到 這個 Bug 的原因。

關於 Migration

關於 Migration 的意思,我自己是想成「這個檔案在對資料庫做什麼?(或是資料庫該怎麼變的腳本)」來記。

此話怎講?來舉個例子。

你一開始應該都會用 npx sequelize-cli model:generate --name Model 來建立 Model 的基本結構,這時候會 Sequelize 會順便產生一個 Migation,沒意外應該會叫做 <date>-create-<model>.js 的名稱,而它的內容應該會長得像這樣:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
'use strict';
module.exports = {
// db:migrate 執行這段
async up(queryInterface, Sequelize) {
await queryInterface.createTable('Categories', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER
},
name: {
type: Sequelize.STRING
},
createdAt: {
allowNull: false,
type: Sequelize.DATE
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE
}
});
},
// db:migrate:undo 執行這段
async down(queryInterface, Sequelize) {
await queryInterface.dropTable('Categories');
}
};

仔細看你會發現它其實只是一個用 JS 來執行 SQL 的內容,當執行 db:migrate 時會執行到 up;執行 db:migrate:undo 時會執行到 down

所以這個 Migration 就可以看成是「到資料庫建立 table」的檔案,你要建 table 就執行 db:migrate,要刪除就執行 db:migrate:undo,就是這麼簡單!

那為什麼常常會說它是一種「版本紀錄」?因為你一看 Migration 就能知道「在什麼時間點對資料庫做了什麼改變」,像上面的 <date>-create-<model>.js 就明顯代表「我在某個時間點對資料庫建立了一個 Table」。

舉例來說,如果我現在對 Table 新增了一些欄位或是修改,那我也會有新的 migration,可能叫做 modify_users_add_new_fields 之類的,一目了然。

當你有一大堆 Migation 的時候可能會像這樣:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
20190329025948-create-user.js -> 建立 user 這個 table
20190329054042-create-announcement.js -> 建立 announcement 這個 table
20190329071502-create-progression.js -> 建立 progression 這個 table
20190329080415-create-report.js -> 建立 report 這個 table
20200328083208-update-user-role.js -> 修改 user 這個 table
20200329094946-create-homework.js -> 建立 homework 這個 table
20200423131738-update-user-status.js -> 修改 user 這個 table
20200503085305-update-homeworks-like.js -> 修改 homework 這個 table
20210316055432-create-unit_permissions.js -> 建立 unit_permissions 這個 table
20210316063420-create-note.js -> 建立 note 這個 table
20210405132446-create-syllabus.js -> 建立 syllabus 這個 table
20210530085648-update-user-transaction.js -> 修改 user 這個 table
20210530090402-create-transaction.js -> 建立 transaction 這個 table
20210804121734-create-article.js -> 建立 article 這個 table
20210804121758-create-comment.js -> 建立 comment 這個 table

(引自 Lidemy 的學習系統

反之,如果沒有 Migration 的話,我就透過 git 的 commit 紀錄一個個去看 Model 的內容是在什麼時候被改的,非常非常非常麻煩吧?所以這就是 Migration 的用途。

以上就是 Model 跟 Migration 的差別,不知道我說清楚了沒有,但希望能幫助跟我一樣卡很久的人解惑。

Sequelize 透過 Migration 來修改 Table 資訊 Express 設定靜態檔案的方式
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×