http://www.manongjc.com/detail/56-tqgkihqhanllyyo.html
本文章向大家介紹在Sequelize中使用遷移,主要內(nèi)容包括其使用實(shí)例、應(yīng)用技巧、基本知識(shí)點(diǎn)總結(jié)和需要注意事項(xiàng),具有一定的參考價(jià)值,需要的朋友可以參考一下。
Sequelize是Nodejs生態(tài)中一個(gè)比較出名的ORM框架。通過ORM框架,可以使用對(duì)象來操作數(shù)據(jù)庫表數(shù)據(jù),提高了開發(fā)效率和代碼可讀性,也方便后期維護(hù)。
今天主要介紹通過遷移[Migration]
來創(chuàng)建數(shù)據(jù)庫,表。
遷移的好處,可以類比git。通過每次創(chuàng)建遷移文件,來支持更新,回滾數(shù)據(jù)庫表結(jié)構(gòu),也方便協(xié)同開發(fā),也避免人工手動(dòng)去直接修改數(shù)據(jù)庫,用代碼自動(dòng)管理。換個(gè)電腦,也不用去拷貝數(shù)據(jù)庫,直接運(yùn)行遷移就可以完全恢復(fù)開發(fā)環(huán)境,極大減輕了心智負(fù)擔(dān)。
mkdir node_work
cd node_work
mkdir appnpm init -ynpm i sequelize-cli sequelize mysql2 koa
npx sequelize init
運(yùn)行之后,會(huì)產(chǎn)生四個(gè)目錄:
config, migrations, models, seeders
config:
{
'development': {
'username': 'root',
'password': 'root',
'database': 'app_development',
'host': '127.0.0.1',
'port': 8889,
'dialect': 'mysql',
'timezone': '+08:00'
},
'test': {
'username': 'root',
'password': null,
'database': 'app_test',
'host': '127.0.0.1',
'dialect': 'mysql'
},
'production': {
'username': 'root',
'password': null,
'database': 'app_production',
'host': '127.0.0.1',
'dialect': 'mysql'
}}
環(huán)境env => {配置}
不同環(huán)境,對(duì)應(yīng)不同的配置,也可以自定義環(huán)境,比如home
env指的是process.env.NODE_ENV
,
可以通過設(shè)置環(huán)境變量來改變,比如export NODE_ENV=production
;
遷移時(shí)候,也可以指定環(huán)境:npx sequelize db:migrate --env production
,來連接production對(duì)應(yīng)配置的數(shù)據(jù)庫
創(chuàng)建數(shù)據(jù)庫:
npx sequelize db:create
說明
npx
是npm5.2之后,自帶的一個(gè)命令??梢圆挥萌职惭bsequelize,使用時(shí)候,如果本地沒有,就去npm倉庫下載;下載完后或者本地已經(jīng)下載過,就運(yùn)行腳本命令。這樣可以避免本地全局包過期,環(huán)境問題,每次都使用最新版本
migrations: 遷移文件
npx sequelize model:generate --name User --attributes username:string
執(zhí)行后,會(huì)生成20180918055558-create-user.js
遷移文件,和models/user.js
模型文件
其他字段可以在遷移文件中補(bǔ)全,最后再運(yùn)行npx sequelize db:migrate
,就可以在數(shù)據(jù)庫中看到生成了users表
'use strict'; module.exports = { up: (queryInterface, Sequelize) => { return queryInterface.createTable('Users', { id: { allowNull: false, autoIncrement: true, primaryKey: true, type: Sequelize.INTEGER }, username: { type: Sequelize.STRING(20), allowNull: false }, password: { type: Sequelize.CHAR(32), allowNull: false }, createdAt: { allowNull: false, type: Sequelize.DATE }, updatedAt: { allowNull: false, type: Sequelize.DATE } }, { tableName: 'users', charset: 'utf8mb4', collate: 'utf8mb4_bin', define: { timestamps: true } }).then(() => { // 添加索引 return queryInterface.addIndex('users', { name: 'username', unique: true, fields: ['username'] }); }); }, // 回退時(shí)執(zhí)行,刪除表 down: (queryInterface, Sequelize) => { return queryInterface.dropTable('Users'); } };
執(zhí)行遷移:
npx sequelize db:migratenpx sequelize db:migrate:all
撤銷遷移:
npx sequelize db:migrate:undo 最近一次的npx sequelize db:migrate:undo:allnpx sequelize db:migrate:undo:all --to XXXXXXXXXXXXXX-create-posts.js
--from, --to
參數(shù),可以指定遷移文件
models: 模型文件
model:generate
生成的model都在這個(gè)目錄中
'use strict';module.exports = { up: (queryInterface, Sequelize) => { return queryInterface.createTable('Users', { id: { allowNull: false, autoIncrement: true, primaryKey: true, type: Sequelize.INTEGER
}, username: { type: Sequelize.STRING(20), allowNull: false
}, password: { type: Sequelize.CHAR(32), allowNull: false
}, createdAt: { allowNull: false, type: Sequelize.DATE
}, updatedAt: { allowNull: false, type: Sequelize.DATE
}
},
{ tableName: 'users', charset: 'utf8mb4', collate: 'utf8mb4_bin',
}).then(() => { return queryInterface.addIndex('users', { name: 'username', unique: true, fields: ['username']
});
});
}, down: (queryInterface, Sequelize) => { return queryInterface.dropTable('Users');
}
};
模型對(duì)象創(chuàng)建,默認(rèn)會(huì)自動(dòng)賦值,更新createdAt, updatedAt兩個(gè)timestamps字段。下邊會(huì)給出完整示例。
seeders: 填充數(shù)據(jù)文件
創(chuàng)建seed文件:
npx sequelize seed:generate --name demo-user
執(zhí)行之后,會(huì)得到20180918090545-demo-user.js
'use strict';const md5 = require('md5')module.exports = {
up: (queryInterface, Sequelize) => { return queryInterface.bulkInsert('Users', [
{
username: 'Kimoo',
password: md5('123456'),
createdAt: new Date(),
updatedAt: new Date(),
},
{
username: 'Reci',
password: md5('123321'),
createdAt: new Date(),
updatedAt: new Date(),
}
], {});
},
down: (queryInterface, Sequelize) => { /*
Add reverting commands here.
Return a promise to correctly handle asynchronicity.
Example:
return queryInterface.bulkDelete('Person', null, {});
*/
return queryInterface.bulkDelete('Users', null, {});
}
};
填充數(shù)據(jù):
npx sequelize db:seed:all
撤銷數(shù)據(jù):
npx sequelize db:seed:undo 最近一次的npx sequelize db:seed:undo --seed name-of-seed-as-in-data 具體某個(gè)npx sequelize db:seed:undo:all
app.js
(async function() { const Koa = require('koa'); const KoaStaticCache = require('koa-static-cache'); const KoaBodyParser = require('koa-bodyparser'); const router = require('./routers/main'); const Session = require('koa-session'); const app = new Koa(); // app.keys = new KeyGrip(['im a newer secret', 'i like turtle'], 'sha256'); app.keys = ['app']; app.use( Session({ key: 'koa:sess', maxAge: 86400000, autoCommit: true, overwrite: true, httpOnly: true, signed: true, rolling: false, renew: false }, app) ); // app.use( async (ctx, next) => { // ctx.set('Access-Control-Allow-Origin','*'); // await next(); // } ); app.use( KoaStaticCache('./public', { prefix: 'public', gzip: true }) ); app.use( KoaBodyParser() ); app.use( router.routes() ); app.listen(8088); })();
models/index.js
'use strict';const fs = require('fs');const path = require('path');const Sequelize = require('sequelize');const basename = path.basename(__filename);const env = process.env.NODE_ENV || 'development';const config = require(__dirname + '/../config/config.json')[env];const db = {};let sequelize;if (config.use_env_variable) {
sequelize = new Sequelize(process.env[config.use_env_variable], config);
} else {
sequelize = new Sequelize(config.database, config.username, config.password, config);
}// 自動(dòng)導(dǎo)入 models 文件夾下的所有文件,比如user.js這個(gè)模型文件// 自動(dòng)加載模型并執(zhí)行// let users = require('./users');// let UsersModel = users(sequelize, Sequelize);// db[UsersModel.name] = UsersModel; // db['Users'] = UsersModel;// 下面通過fs自動(dòng)加載所有的文件,并執(zhí)行,同時(shí)生成的模型對(duì)象掛載到db對(duì)象下面,最后返回出去fs
.readdirSync(__dirname)
.filter(file => { return (file.indexOf('.') !== 0) && (file !== basename) && (file.slice(-3) === '.js');
})
.forEach(file => { const model = sequelize['import'](path.join(__dirname, file));
db[model.name] = model;
});Object.keys(db).forEach(modelName => { if (db[modelName].associate) {
db[modelName].associate(db);
}
});
db.sequelize = sequelize;
db.Sequelize = Sequelize;module.exports = db;
routers/main.js
const KoaRouter = require('koa-router');const md5 = require('md5');const Models = require('../models');const Sequelize = require('sequelize');const router = new KoaRouter(); router.post('/register', async ctx => { // console.log(ctx.request.body); let username = ctx.request.body.username.trim(); let password = ctx.request.body.password.trim(); let repassword = ctx.request.body.repassword.trim(); if (username=='' || password == '' || repassword == '') { return ctx.body = { code: 1, data: '用戶名或密碼不能為空' } } if (password != repassword) { return ctx.body = { code: 2, data: '兩次輸入的密碼不一致' } } let user = await Models.Users.findOne({ where: { username } }); if (user !== null) { return ctx.body = { code: 3, data: '當(dāng)前用戶已經(jīng)被注冊(cè)了' } } let newUser = await Models.Users.build({ username, password: md5(password) }).save(); ctx.body = { code: 0, data: { id: newUser.get('id'), username: newUser.get('username') } } }); router.post('/login', async ctx => { let username = ctx.request.body.username; let password = ctx.request.body.password; let user = await Models.Users.findOne({ where: { username } }); if (user === null) { return ctx.body = { code: 1, data: '不存在該用戶' } } if (user.get('password') !== md5(password)) { return ctx.body = { code: 1, data: '密碼錯(cuò)誤' } } // ctx.cookies.set('uid', user.get('id'), { // httpOnly: false // }); // 服務(wù)端發(fā)送一個(gè)約定好的cookie,來表示當(dāng)前是登錄 // ctx.cookies.set('uid', user.get('id'), { // // httpOnly,表示當(dāng)前的cookie是否允許客戶端進(jìn)行操作(js),如果為true,那么就表示這個(gè)cookie是能用戶http協(xié)議的數(shù)據(jù)傳輸 // httpOnly: true, // signed: true // }); ctx.cookies.set('username', user.get('username'), { httpOnly: false }); ctx.session.uid = 1; ctx.body = { code: 0, data: { id: user.get('id'), username: user.get('username') } } }); }) module.exports = router;
可以在postman
中測(cè)試接口,地址http://localhost:8088/register
,注冊(cè)用戶
node app.js
聯(lián)系客服