希望真的有搞清楚了。
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) { Post.belongsTo(models.Category) } } 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 = { 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 } }); }, 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 的差別,不知道我說清楚了沒有,但希望能幫助跟我一樣卡很久的人解惑。