[Node.js] Sequelize Migration Seeds
Sequelize 是 Node.js 下相當主流的 ORM 套件.
ORM 使用與否的爭論大概也和 Space VS Tab, Vi VS Emacs ... 一樣的永無止盡.
而 Sequelize 2 之後推出 sequelize-cli 中的 Migration 功能, 透過一次又一次的維護檔, 確保移植時有相同的建構過程, 確實能解決程式開發階段對資料庫操作的常見困擾:
- 出問題回不到上個版本?
- 忘記做了哪些修改?
- 改了 schema 沒人知道?
什麼是 Migraiton ?
- Migration 是用來描述 「資料庫的結構掌什麼樣子」 的檔案, 隨著專案開發過程中對資料庫的修改而逐漸增加.
- 可以理解成資料庫格式變更的版本控制.
操作行為
Migration 是拿來變動資料表的, 所以會有幾種動作在這裡處理.
- 變動資料表
- 變動欄位
- 變動資料表關聯
可以幹嘛
- 紀錄操作過程
- 降低人為操作錯誤的可能
- 環境部署或是更換資料庫的時候,快速達成同步
- 錯誤發生時,可以快速回到正確的版本
環境安裝與設置
sequelize-cli
sequelize-cli 可系統全域安裝或安裝在專案項目, 依實際需求而定.
npm install --save-dev sequelize-cli
亦直接透過 npx sequelize 執行.
Project bootstrapping
npx sequelize-cli init
This will create following folders
config, contains config file, which tells CLI how to connect with databasemodels, contains all models for your projectmigrations, contains all migration filesseeders, contains all seed files
configure
修改 config/config.json 裡頭連接 DB 的相關配置.
"development": {
"username": "user",
"password": "password",
"database": "database name",
"host": "127.0.0.1",
"dialect": "mysql"
},
設定完後即可利用 sequelize 來操作 DB. 如新建一張 user table
sequelize model:generate --name user --attributes name:string,mail:string
基本使用指令
透過下列指令可新增 migration, 並且想好 migration message.
sequelize migration:create --name <migration message>
就會產生檔案 migrations/<YYYYMMDDHHMMSS>-<migration message>.js.
用自己習慣的編輯器去修改 js, 搭配 Query Interface 語法去建立或調整資料庫 Schema 修改.
sequelize db:migrate
這個指令會自動執行到最後一個 migration.js 檔案裡面的 up(), 為資料庫欄位逐次修改調整過程.
sequelize db:migrate:undo
則執行 js 檔案裡面的 down(), 內容為對應修改的還原語法.
指令列表
Sequelize CLI [Node: 16.17.0, CLI: 6.4.1, ORM: 6.21.6]
sequelize <command>
Commands:
sequelize db:migrate Run pending migrations
sequelize db:migrate:schema:timestamps:add Update migration table to have timestamps
sequelize db:migrate:status List the status of all migrations
sequelize db:migrate:undo Reverts a migration
sequelize db:migrate:undo:all Revert all migrations ran
sequelize db:seed Run specified seeder
sequelize db:seed:undo Deletes data from the database
sequelize db:seed:all Run every seeder
sequelize db:seed:undo:all Deletes data from the database
sequelize db:create Create database specified by configuration
sequelize db:drop Drop database specified by configuration
sequelize init Initializes project
sequelize init:config Initializes configuration
sequelize init:migrations Initializes migrations
sequelize init:models Initializes models
sequelize init:seeders Initializes seeders
sequelize migration:generate Generates a new migration file
sequelize migration:create Generates a new migration file
sequelize model:generate Generates a model and its migration
sequelize model:create Generates a model and its migration
sequelize seed:generate Generates a new seed file
sequelize seed:create Generates a new seed file
Options:
--version Show version number [boolean]
--help Show help
檔案架構
up() down() 都回傳 promise
'use strict';
module.exports = {
up: (queryInterface, Sequelize) => {
// 要增加內容的動作
},
down: (queryInterface, Sequelize) => {
// 要減少內容的動作
}
};
Query Interface 常用方法
- 變動資料表
- 新增資料表
createTable(tableName, attributes, options) - 刪除資料表
dropTable(tableName, options) - 刪除所有資料表
dropAllTables(options) - 重新命名資料表
renameTable(before, after, options) - 顯示資料表陣列
showAllTables(options)- tableNames 的 datatype Array
- 顯示資料表 schema
describeTable(tableName, options)
- 新增資料表
- 變動欄位
- 增加欄位
addColumn(tableName, attributeName, dataTypeOrOptions, options) - 刪除欄位
removeColumn(tableName, attributeName, options) - 修改欄位設定
changeColumn(tableName, attributeName, dataTypeOrOptions, options) - 重新命名欄位
renameColumn(tableName, attrNameBefore, attrNameAfter, options)
- 增加欄位
- 變動索引(資料表屬性的功能)
- 建立索引
addIndex(tableName, attributes, options) - 移除索引
removeIndex(tableName, indexNameOrAttributes, options)
- 建立索引
SQL 語法
除了呼叫 Query Interface 外, 使用 queryInterface.sequelize.query(SQL 語法) 的用法,
可以直接執行 SQL 語法, 補足 Query Interface 方法的不足.
或因故不想透過 Sequelize ORM 語法時, 可直接使用標準 SQL 來更改資料庫 Schema.
up: (queryInterface, Sequelize) => {
return queryInterface.method(
//...
}).then(() => {
queryInterface.sequelize.query(`UPDATE table SET column=field`)
})
}
進階使用
回朔版本
可以建立也可以回溯
- sequelize db:migrate:undo 一次退一個版本
- sequelize db:migrate:undo:all 退到初始狀態
- sequelize db:migrate:undo:all --to XXXXXXXXXXXXXX-create-user.js 退到指定版本
資料表關聯
在 queryInterface.createTable / addColumn 中, 在 attributes 定義欄位的物件中, 寫 reference 決定資料庫變動後, 關聯是否存在.
return queryInterface.addColumn(
'tableName',
'fieldName',
{
type: Sequelize.INTEGER.UNSIGNED,
references: {
model: 'tableName',
key: 'fieldName'
},
onDelete: 'SET NULL',
onUpdate: 'CASCADE'
//...
})
},
Hook
當呼叫 add/set 函數時, beforeUpdate/afterUpdate 也會執行. 唯一可以執行 beforeDestroy/afterDestroy 的方式, 就是設定 associations 屬性 onDelete: ‘cascade’. 參考: http://docs.sequelizejs.com/manual/tutorial/hooks.html
呼叫 association 時設定 hook 選項, ex: onUpdate, onDelete.
預設所有的關聯, 更新用 CASCADE, 刪除用 SET NULL, 除了 n:m 關聯, 用 CASCADE 刪除.
RESTRICT, 同 NO ACTIONCASCADE, 同步 update/delete 更新子表 foreign keyNO ACTION, 不允許主表 update/deleteSET DEFAULT, 子表 foreign key 設為 default (Innodb not use)SET NULL, 子表 foreign key 設為 null
Available constraints:
- UNIQUE
queryInterface.addConstraint('Users', ['email'], {
type: 'unique',
name: 'custom_unique_constraint_name'
}); - DEFAULT (MSSQL only)
queryInterface.addConstraint('Users', ['roles'], {
type: 'default',
defaultValue: 'guest'
}); - CHECK (MySQL - Ignored by the database engine)
queryInterface.addConstraint('Users', ['roles'], {
type: 'check',
where: {
roles: ['user', 'admin', 'moderator', 'guest']
}
}); - FOREIGN KEY
queryInterface.addConstraint('Posts', ['username'], {
type: 'foreign key',
name: 'custom_fkey_constraint_name',
references: { //Required field
table: 'target_table_name',
field: 'target_column_name'
},
onDelete: 'cascade',
onUpdate: 'cascade'
}); - PRIMARY KEY
queryInterface.addConstraint('Users', ['username'], {
type: 'primary key',
name: 'custom_primary_constraint_name'
});
See Also
雖然 Migration 是 Sequelize 所推出的, 但 sequelize-cli 可獨立使用. 使用 Sequelize Migration 來管理專案資料庫格式架構和程式中是否使用 Sequelize ORM 並無關係.
不喜使用 ORM 的開發者或既有的專案, 無須改變存取資料庫的方式,
程式可以不透過 Sequelize ORM, 自行處理資料庫存取介面.
專案也可以不依賴 qequelize-cli,
直接透過 npx sequelize COMMAND [OPTIONS] 來執行 Sequelize Migration.