利用傳說中的ORM技術,把關聯式資料庫的表結構對映到物件上,簡化資料庫操作。
Published: 2019-3-01
Sequelize 是一個基於 Prom 的 ORM for Node,面向熟悉 JavaScript 和使用 Node.js 進行後端開發的開發人員。在本篇文章中,將探討 Sequelize 的一些常見用例以及 利用 Sequelize-cli 完成相關的環境配置。
- Sequelize 極簡入門教程;
- Sequelize-cli 完成 dev,test,prod 環境的配置,以及資料庫建立;
- Sequelize-cli 完成表結構的設計、遷移與資料填充;
- Sequelize 結合 Sequelize-cli 完成資料庫的增、刪、改、查;
- 總結。
Sequelize 極簡入門教程
本章程式碼,here
ORM:Object-Relational Mapping,就是允許將關聯式資料庫對映到物件上,使得這些物件具有一些屬性和運算元據庫的方法,避免編寫 SQL 語句。
Sequelize:Sequelize 是一款基於 Nodejs 功能強大的非同步ORM框架,同時支援 PostgreSQL,MySQL,SQLite 等多種資料庫,很適合作為Nodejs後端資料庫的儲存介面。
本節簡單利用 Sequelize 向資料庫中插入一條資料,方便後續理解 Sequelize-cli。
安裝
可以利用 npm
或 yarn
完成安裝
// Using NPM
$ npm install --save sequelize
# And one of the following:
$ npm install --save pg pg-hstore
$ npm install --save mysql2
$ npm install --save sqlite3
$ npm install --save tedious // MSSQL
// Using Yarn
$ yarn add sequelize
# And one of the following:
$ yarn add pg pg-hstore
$ yarn add mysql2
$ yarn add sqlite3
$ yarn add tedious // MSSQL
複製程式碼
本文依賴 mysql
,所以
$ npm install --save sequelize
$ npm install --save mysql2
複製程式碼
建立與資料庫連線
Sequelize 提供了兩種連線資料庫的方式
const Sequelize = require('sequelize');
// 資料庫相關引數
const sequelize = new Sequelize('database', 'username', 'password', {
// 所在ip
host: 'localhost',
// 所用埠
port: '埠',
// 所用資料庫型別
dialect: 'mysql'|'sqlite'|'postgres'|'mssql',
// 請參考 Querying - 查詢 操作符 章節
operatorsAliases: false,
// 設定連線池,因此如果您從單個程式連線到資料庫,理想情況下應該只為每個資料庫建立一個例項
pool: {
max: 5,
min: 0,
acquire: 30000,
idle: 10000
},
// 執行過程會log一些SQL的logging,設為false不顯示
logging: false,
// SQLite only
storage: 'path/to/database.sqlite'
});
// 利用 uri 簡易連線資料庫
const sequelize = new Sequelize('postgres://user:pass@example.com:5432/dbname');
複製程式碼
本文所用資料庫為 mysql,結合 sequelize.authenticate
來對連線進行測試,構建 index.js
const Sequelize = require('sequelize');
const sequelize = new Sequelize('users_dev', 'username', 'password', {
host: 'localhost',
port: 3306,
dialect: 'mysql',
operatorsAliases: false,
// logging: false,
pool: {
max: 5,
min: 0,
acquire: 30000,
idle: 10000
},
});
sequelize
.authenticate()
.then(() => {
console.log('Connection has been established successfully.');
process.exit();
})
.catch(err => {
console.error('Unable to connect to the database:', err);
});
複製程式碼
利用 node index.js
執行該指令碼,成功的會列印出 Connection has been established successfully.
。
定義 Model,並插入資料
Model 主要是用來完成與表之間的對映,主要利用 sequelize.define('name', {attributes}, {options})
完成 Model 的定義。我們定義一個 User
模型對應 user
表。
const User = sequelize.define('user', {
// 即使表的結構也是Model的屬性
firstName: {
type: Sequelize.STRING
},
lastName: {
type: Sequelize.STRING
}
});
複製程式碼
利用已經定義好的Model,可以完成對 user
表的插入資料操作
// force: true will drop the table if it already exists
User.sync({
force: true
}).then(() => {
// Table created
return User.create({
firstName: 'John',
lastName: 'Hancock'
});
}).then(() => {
process.exit()
})
複製程式碼
以上完成 Sequelize 的極簡介紹,主要想介紹一個對映的流向,方便後續理解,官網例項更加詳細。
Sequelize-cli 完成 dev,test,prod 環境的配置,以及資料庫建立
本章程式碼,here
與 Sequelize 相伴的有 Sequelize-cli 工具,Sequelize-cli 為我們提供了一系列好用的終端指令,來完成以下工作
- 配置不同的環境的資料庫連線,例如dev、test、prod等;
- 自動管理表對應的 Model;
- 利用 migrations 完成資料庫的表結構的遷移;
- 利用 seeders 完成資料庫的表內容的初始化。
首先安裝 Sequelize-cli
npm i sequelize-cli -D
複製程式碼
在 package.json 中新增
"scripts": {
"init": "node_modules/.bin/sequelize init",
...
}
複製程式碼
執行 npm run init
命令,之後會發現,在目錄下多了 config、models、migrations、seeders四個資料夾
├── config # 專案配置目錄 | ├── config.json # 資料庫連線的配置 ├── models # 資料庫 model | ├── index.js # 資料庫連線的樣板程式碼 ├── migrations # 資料遷移的目錄 ├── seeders # 資料填充的目錄
本節只考慮配置相關的,也就是config資料夾下的內容,主要包含 config.json
{
"development": {
"username": "root",
"password": null,
"database": "database_development",
"host": "127.0.0.1",
"dialect": "mysql"
},
"test": {
"username": "root",
"password": null,
"database": "database_test",
"host": "127.0.0.1",
"dialect": "mysql"
},
"production": {
"username": "root",
"password": null,
"database": "database_production",
"host": "127.0.0.1",
"dialect": "mysql"
}
}
複製程式碼
主要包含了 development、test、production,三個環境下的資料庫資訊。
之前我也是利用 config.json 來管理的,但是之後通過閱讀基於 hapi 的 Node.js 小程式後端開發實踐指南,發現利用 .env 檔案來管理是一種更為優雅的方法。
安裝 env2 外掛,在當前目錄下建立 .env 檔案用於配置開發環境以及生產環境的基礎資訊。
npm i -D env2
複製程式碼
.env 內容,注字串變數不需要''。
DB_USERNAME = username
DB_PASSWORD = password
DB_NAME = dataname
DB_NAME_PROD = prodDataname
DB_HOST = *.*.*.*
DB_PORT = *
複製程式碼
如果 git 非私密的,需要配置 .gitignore 的相關資訊,在config檔案下,建立config.js
require('env2')('./.env');
const {
env
} = process;
module.exports = {
"development": {
"username": env.DB_USERNAME,
"password": env.DB_PASSWORD,
"database": env.DB_NAME,
"host": env.DB_HOST,
"port": env.DB_PORT,
"dialect": "mysql",
"operatorsAliases": false,
},
"production": {
"username": env.DB_USERNAME,
"password": env.DB_PASSWORD,
"database": env.DB_NAME_PROD,
"host": env.DB_HOST,
"port": env.DB_PORT,
"dialect": "mysql",
"operatorsAliases": false,
}
}
複製程式碼
同時修改models資料夾下的index.js
// .json => .js
const config = require(__dirname + '/../config/config.js')[env];
複製程式碼
以上利用env2完成對開發環境,生產環境的config配置,新增 create
以及 create:prod
兩條指令
"scripts": {
"init": "node_modules/.bin/sequelize init",
"create": "node_modules/.bin/sequelize db:create",
"create:prod": "node_modules/.bin/sequelize db:create --env production",
...
}
複製程式碼
可建立開發環境、生產環境的的資料庫。
Sequelize-cli 完成表結構的設計、遷移與資料填充
本章程式碼,here
表結構的設計、遷移都與 Migrations 相關
就像使用Git / SVN管理原始碼中的更改一樣,可以使用 Migration 來初始化資料庫、或跟蹤資料庫更改,也就是說通過配置 Migration 檔案可以將現有資料庫遷移至另一個狀態,並且儲存記錄。
"scripts": {
...
"migration": "node_modules/.bin/sequelize migration:create --name create-examples-table",
"migration:prod": "node_modules/.bin/sequelize migration:create --name create-examples-table --env production"
...
}
複製程式碼
首先在開發環境下進行測試,執行 npm run migration
指令,之後會在 migrations 資料夾內建立一個20190301054713-create-examples-table.js 檔案,內容為
'use strict';
module.exports = {
up: (queryInterface, DataTypes) => {
/*
Example:
return queryInterface.createTable('users', { id: DataTypes.INTEGER });
*/
},
down: (queryInterface, DataTypes) => {
/*
Example:
return queryInterface.dropTable('users');
*/
}
};
複製程式碼
模組暴漏出一個物件,包含著 up
、down
兩個方法,up
用於定義表結構正向改變,down
則用於定義表結構的回退,對應其中的 return
,正向 createTable
,反向則是 dropTable
。
兩個引數的定義:
-
queryInterface:用於定義Sequelize與所屬資料庫通訊的介面,包含一些API,例如
createTable
用於建立表,dropTable
則用於撤銷,addColumn
用於追加欄位,removeColumn
則用於移除; -
DataTypes:用於定義介面資料的型別。
queryInterface.createTable(...)
整體功能與 sequelize.define(...)
類似。簡單設計如下表
'use strict';
module.exports = {
up: (queryInterface, DataTypes) => {
return queryInterface.createTable('users', {
id: {
type: DataTypes.INTEGER,
autoIncrement: true,
primaryKey: true,
},
name: {
type: DataTypes.STRING,
allowNull: false,
},
created_at: DataTypes.DATE,
updated_at: DataTypes.DATE,
});
},
down: (queryInterface) => {
return queryInterface.dropTable('users');
}
};
複製程式碼
新增如下指令
"scripts": {
...
"migrate": "node_modules/.bin/sequelize db:migrate",
"migrate:prod": "node_modules/.bin/sequelize db:migrate --env production",
...
}
複製程式碼
執行 npm run migrate
,會將 migrations 目錄下的遷移行為定義,按時間戳的順序,逐個地執行遷移描述,最終完成資料庫表結構的自動化建立。會發現資料庫examples_dev內建立了一張 SequelizeMeta 的表以及 users 的表:
- SequelizeMeta:記錄了對應遷移檔案的資訊;
- users:是利用
queryInterface.createTable
建立的表。
相應的也有 node_modules/.bin/sequelize db:migrate:undo
來撤銷相應的遷移,這裡就不展開介紹了。
資料填充
主要利用 seeders 來在初始化資料表中中初始化一些基礎資料,使用方式與資料庫表結構遷移相似,新增如下指令。
"scripts": {
...
"seeder": "node_modules/.bin/sequelize seed:create --name init-users",
"seeder:prod": "node_modules/.bin/sequelize seed:create --name init-users --env production",
...
}
複製程式碼
執行 npm run seed
指令,則與資料遷移相同的是,seeders 資料夾下多了一個 ***init-users.js 檔案,結構也和資料遷移類似。
'use strict';
module.exports = {
up: (queryInterface, Sequelize) => {
/*
Example:
return queryInterface.bulkInsert('People', [{
name: 'John Doe',
isBetaMember: false
}], {});
*/
},
down: (queryInterface, Sequelize) => {
/*
Example:
return queryInterface.bulkDelete('People', null, {});
*/
}
};
複製程式碼
引數也相同,只不過一個是建立表,一個是建立資料,所利用的API不同而已,例如。
'use strict';
module.exports = {
up: (queryInterface, Sequelize) => {
return queryInterface.bulkInsert('users', [{
name: 'John Doe',
created_at: new Date(),
updated_at: new Date()
}], {});
},
down: (queryInterface, Sequelize) => {
return queryInterface.bulkDelete('users', null, {});
}
};
複製程式碼
新增指令
"scripts": {
...
"seed": "node_modules/.bin/sequelize db:seed:all",
"seed:prod": "node_modules/.bin/sequelize db:seed:all --env production",
...
}
複製程式碼
也可以用 node_modules/.bin/sequelize db:seed --seed xxxxxxxxx-init-users.js
來指定添充資料。
Sequelize 結合 Sequelize-cli 完成資料庫的增、刪、改、查
本章程式碼,here
在第一節中,簡單介紹了 User.create(...)
插入了一條資料,本節中介紹結合 Sequelize-cli 完成對資料庫的增、刪、改、查。
在 Models 資料夾下建立對應的模型檔案 users.js,內容與第一節 sequelize.define(...)
類似
module.exports = (sequelize, DataTypes) => sequelize.define(
'users', {
id: {
type: DataTypes.INTEGER,
autoIncrement: true,
primaryKey: true,
},
name: {
type: DataTypes.STRING,
allowNull: false,
}
}, {
tableName: 'users',
// 以下兩個屬性是針對createAt、updateAt這兩個預設屬性的,timestamps是不使用,而underscored
// 則是將createAt轉化為create_at
// timestamps: false,
underscored: true,
}
)
複製程式碼
模型結構,與資料遷移相同,在 index.js 檔案內引入模型
const { users } = require("./models");
複製程式碼
可以利用該 Model 完成對錶 users 的操作,主要以下幾個
-
查:
findAll
、findByPk
、findCreateFind
、findOrCreate
.....const { users } = require("./models"); (async () => { // 搜尋多個例項 const user = await users.findAll() // 條件搜尋name = 'John Doe' // const user = await users.findByPk(1) console.log(user) process.exit(); })() 複製程式碼
-
增:
create
、bulkCreate
....const { users } = require("./models"); (async () => { await users.create({ name: 'Yang' }) process.exit(); })() 複製程式碼
-
刪:
destroy
、drop
刪表.....const { users } = require("./models"); (async () => { await users.destroy({ where: { name: 'Yang' } }) process.exit(); })() 複製程式碼
-
改:
upsert
,update
.....const { users } = require("./models"); (async () => { await users.update({ name: 'Yange' }, { where: { name: 'John Doe' } }) /* await users.upsert({ name: 'Sccc' }, { where: { name: 'Yange' } }) */ process.exit(); })() 複製程式碼
總結
這篇主要是用來總結之前一直看到的零散知識,也是用來配置存底,防止自己忘了。之前用的 mongoose 到 Sequelize,感覺自己一直在切換工具,卻又沒有很好地入門瞭解。之後應該是會選擇一個點深入瞭解下吧,對自己很是失望。
參考
http://docs.sequelizejs.com/class/lib/model.js~Model.html#static-method-upsert
https://juejin.im/book/5b63fdba6fb9a04fde5ae6d0/section/5b6c048e6fb9a04fdc36afc1