本文為 Lidemy [BE201] 之 [ORM 與 Sequelize] 讀書筆記,內含基本介紹及如何使用。
零、基本介紹
ORM 全稱為 Object Relational Mapping,是一種把資料庫轉換成物件並且關聯對映的方法,接下來要用 Sequelize 這個框架來實作 ORM。
一、實作 Sequelize 建立一個 ORM
1. 基本設置
a. 安裝 sequelize & database $ npm install --save sequelize
、$ npm install --save mysql2
b. 引入並建立連線
const Sequelize = require('sequelize');
const sequelize = new Sequelize('mydb', 'username', 'password', {
host: 'localhost',
dialect: 'mysql'
})
c. 看範例把程式碼拿進來:Using sequelize.define,查詢文件設定 Model Definition
const User = sequelize.define('user', {
firstName: {
type: Sequelize.STRING,
allowNull: false
},
lastName: {
type: Sequelize.STRING
}
});
d. 呼叫 sequelize 幫你建立 table sequelize.sync()
sequelize.sync().then(() => {
User.create({
firstName: 'John',
lastName: 'Hancock'
}).then(() => {
console.log('created!')
})
})
下面訊息就代表已經建立完成了,在資料庫裡面會有一個 users 的表格
Executing (default): CREATE TABLE IF NOT EXISTS `users` (`id` INTEGER NOT NULL auto_increment , `firstName` VARCHAR(255) NOT NULL, `lastName` VARCHAR(255), `createdAt` DATETIME NOT NULL, `updatedAt` DATETIME NOT NULL, PRIMARY KEY (`id`)) ENGINE=InnoDB;
Executing (default): SHOW INDEX FROM `users`
Executing (default): INSERT INTO `users` (`id`,`firstName`,`lastName`,`createdAt`,`updatedAt`) VALUES (DEFAULT,?,?,?,?);
created!
2. 如何操作 sql query
Model Querying - Basics: 這裡示範了怎麼操作 CRUD
Model Querying - Finders: 常用用法,例如 findAll()
、findOne()
a. 找尋所有使用者:
sequelize.sync().then(() => {
User.findAll().then(users => {
console.log(users[0].id, users[0].firstName)
})
})
設定條件,寫在 findAll()
裡面:
sequelize.sync().then(() => {
User.findAll({
where: {
firstName: 'John'
}
}).then(users => {
console.log(users[0].id, users[0].firstName)
})
})
b. findOne()
+ update()
sequelize.sync().then(() => {
User.findOne({
where: {
firstName: 'John'
}
}).then(user => {
user.update({
lastName: 'Elvis'
})
}).then(() => {
console.log('done')
})
})
c. destroy()
sequelize.sync().then(() => {
User.findOne({
where: {
firstName: 'John'
}
}).then(user => {
user.destroy().then(() => {
console.log('done')
})
})
})
二、建立資料庫關聯 Associations
1. 資料庫裡有兩個表格 comment & user,使用 User.hasMany(Comment)
建立關聯
下了指令後,會自動生成一個 Comments 的表格,內含 id, content, createdAt, updatedAt, userId
const User = sequelize.define('user', {
firstName: {
type: Sequelize.STRING,
allowNull: false
},
lastName: {
type: Sequelize.STRING
}
});
const Comment = sequelize.define('comment', {
content: {
type: Sequelize.STRING,
}
});
User.hasMany(Comment)
2. 新增一個 UserId & content
這裡不知道為什麼無法新增,錯誤訊息是:(node:5520) UnhandledPromiseRejectionWarning: Error,先跳過,不要卡在這裡。
就在放棄的時候,我找到解答了,原來是我的 users 表格裡面,只有 id 為 2 & 3 的使用者,那當我要新增 userId 為 1 時,就會有錯誤。
const Sequelize = require('sequelize');
const sequelize = new Sequelize('mydb', 'christy', 'password', {
host: 'localhost',
dialect: 'mysql'
})
const User = sequelize.define('user', {
firstName: {
type: Sequelize.STRING,
allowNull: false
},
lastName: {
type: Sequelize.STRING
}
});
const Comment = sequelize.define('comment', {
content: {
type: Sequelize.STRING,
}
});
User.hasMany(Comment)
sequelize.sync().then(() => {
Comment.create({
// 問題是我沒有 user id 為 1 的使用者,只有 2 & 3
// 改成 userId: 2, 就好了
userId: 1,
content: 'hello'
}).then(() => {
// 執行時沒有印出 done,懷疑是語法問題,但是無解
// 後來發現不是這個問題,問題在上面
console.log('done')
})
User.findOne({
where: {
firstName: 'John'
}
}).then(user => {
})
})
3. 尋找評論
在找「這個評論是哪一個使用者發布」時,因為 User.hasMany(Comment)
是一個單向關係,所以必須再加上Comment.belongsTo(User)
才能夠把資料撈出來。
const Sequelize = require('sequelize');
const sequelize = new Sequelize('mydb', 'christy', 'password', {
host: 'localhost',
dialect: 'mysql'
})
const User = sequelize.define('user', {
firstName: {
type: Sequelize.STRING,
allowNull: false
},
lastName: {
type: Sequelize.STRING
}
});
const Comment = sequelize.define('comment', {
content: {
type: Sequelize.STRING,
}
});
User.hasMany(Comment)
Comment.belongsTo(User)
sequelize.sync().then(() => {
Comment.findOne({
where: {
content: 'hello'
},
include: User
}).then(comment => {
console.log(JSON.stringify(comment, null, 4))
})
})
三、Sequelize CLI 實戰 — Migrations
1. 前置作業
如果要從頭來過,記得要從 sequelize 開始安裝
a. $ npm install --save sequelize
b. $ npm install --save mysql2
c. 安裝 Migrations $ npm install --save-dev sequelize-cli
d. 初始化資料夾 $ npx sequelize-cli init
建了四個檔案: config/config.json、models、migrations、seeders
e. 改 config/config.json development 本地開發環境裡面的資料,其他兩個不用改
註:這個檔案不可以 commit 上去喔,因為裡面有帳密
f. Creating the first Model (and Migration)
$ npx sequelize-cli model:generate --name User --attributes firstName:string,lastName:string,email:string
g. Running Migrations
$ npx sequelize-cli db:migrate
註:這裡要注意,每建一個 Model 以後,就要重新跑一次 Migrations 指令(步驟 g)
h. 在 models 裡面的 user.js & comment.js 分別把 associate 寫入
static associate(models) {
User.hasMany(models.Comment)
}
static associate(models) {
Comment.belongsTo(models.User)
}
i. 接著再 migration 資料夾裡面新增一個 index.js 的檔案,就可以寫剛剛學的那些 methods 了
const db = require('./models')
const User = db.User
const Comment = db.Comment
User.create({
firstName: 'hello',
lastName: 'great'
}).then(() => {
console.log('good')
})
j. seeders 種子資料,測網站的資料
四、實作中遇到的 error
Error log 1:
錯誤描述:跑不起來
Error: Please install tedious package manually
try 1: $ npm install tedious
Error(`Please install ${moduleName} package manually`);
try 2: $ npm install ${moduleName}
try 3: $ npm install sqlite3
用官網的 快速範例 可以跑,但是影片中的不行,後來參考官方文件,把程式碼改寫成下面這樣,就成功了。
// sequelize-test.js
const { Sequelize } = require('sequelize');
const sequelize = new Sequelize('mydb', 'christy', 'password', {
host: 'localhost',
dialect: 'mysql'
});
const User = sequelize.define('User', {
firstName: {
type: Sequelize.STRING,
allowNull: false
},
lastName: {
type: Sequelize.STRING
}
}, {
});
(async () => {
await sequelize.sync();
const john = await User.create({
firstName: 'John',
lastName: 'Hancock',
birthday: new Date(1980, 6, 20)
});
console.log(john.toJSON());
})();
註:後來發現是因為我打錯字所以連線失敗!錯字在這裡 dialect: 'mysql'
我打成 'mssql',想辦法改善。
Error log 2:
Sequel Pro 一直無法顯示資料庫,看來是需要等一下,而且有時候 XAMPP 也怪怪的,重開可能可以解決問題,目前是隔天又好了的情況這樣。
Error log 3:
使用 User.hasMany(Comment)
建立兩張表格的關聯時,Comments 裡的 userId 沒有被建立,照著影片做還是有問題,中間雖然發現大小寫問題,但最後跟著影片一模一樣做還是無解,先放著。
就在放棄的時候,我找到解答了,原來是我的 users 表格裡面,只有 id 為 2 & 3 的使用者,那當我要新增 userId 為 1 時,就會有錯誤。