利用 Sequelize 來操作資料庫
利用傳說中的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:[email protected]: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 的表:
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