學會Sequelize,讓你操作數據更絲滑!
本文來介紹 Sequelize,一個基于 Node.js 的 ORM(對象關系映射)工具,并詳細介紹其用法。Sequelize 用于在應用中使用 JavaScript 來操作關系型數據庫,例如 MySQL、PostgreSQL 等。本文內容較多,可作為 Sequelize 的參考手冊來閱讀。
開始使用
核心概念
Sequelize 是一個基于 JavaScript 的 ORM(對象關系映射)庫,用于在 Node.js 環境中與數據庫進行交互。它提供了一種方便、靈活的方式來管理數據庫,并將數據庫表映射為對象,使開發人員可以使用面向對象的編程風格來操作數據庫。
ORM(對象關系映射)是一種編程技術,用于通過將對象和數據庫表之間建立映射關系,以更直觀的方式進行數據庫操作。Sequelize 通過將數據庫記錄映射為模型對象,使得開發人員可以使用 JavaScript 對象的方法和屬性來進行數據庫的增刪改查操作,而不需要編寫復雜的 SQL 查詢語句。
Sequelize 支持多種數據庫,包括 MySQL、PostgreSQL、SQLite 和 MSSQL 等,可以適應各種不同的項目需求。它提供了豐富的功能,包括模型定義、關聯關系、事務處理、查詢構建器等,可以幫助開發人員高效地進行數據庫操作。
使用 Sequelize,開發人員可以輕松地進行數據庫遷移、執行復雜的查詢和聚合操作,并實現數據校驗和驗證等功能。此外,它還提供了鉤子函數、事件觸發和數據庫連接池等功能,以優化數據庫訪問性能。
基本使用
要使用 Sequelize 來連接 MySQL 數據庫,需要進行以下步驟:
- 安裝 Sequelize 和 MySQL 驅動程序:
- 使用 npm 運行以下命令來安裝 Sequelize:npm install sequelize
- 安裝 MySQL:npm install mysql2
- 創建 Sequelize 實例和數據庫連接:
const { Sequelize } = require('sequelize');
const sequelize = new Sequelize('database', 'username', 'password', {
host: 'localhost',
dialect: 'mysql',
});
這里需要將 'database'、'username' 和 'password' 分別替換為 MySQL 數據庫的名稱、用戶名和密碼。還可以根據需要設置其他連接選項,例如 host 和 port。
- 定義模型:
const User = sequelize.define('User', {
username: {
type: DataTypes.STRING,
allowNull: false,
},
email: {
type: DataTypes.STRING,
allowNull: false,
unique: true,
validate: {
isEmail: true,
},
},
// 其他屬性和選項
});
這里定義了一個名為 User 的模型,包含 username 和 email 屬性。
- 進行數據庫操作:
async function createUser() {
await sequelize.sync(); // 同步模型和數據庫
const user = await User.create({ username: 'John', email: 'john@example.com' });
console.log(user.toJSON());
}
createUser().catch(console.error);
這里首先調用 sequelize.sync() 方法來同步模型和數據庫,以確保模型在數據庫中存在。然后使用 User.create() 方法創建一個新用戶,并輸出其序列化后的 JSON 數據。
這只是 Sequelize 連接 MySQL 的基本用法,你還可以使用 Sequelize 提供的其他方法來執行查詢、更新、刪除等操作,以及定義模型之間的關聯關系。下面會詳細介紹!
模型定義
在 Sequelize 中,模型(Model)是一種表示數據庫表結構的抽象化概念。它定義了數據表的結構和行為,包括表名、字段、關聯關系、數據校驗規則等。
Sequelize 模型允許通過編寫模型類來操作數據庫表,封裝了對數據庫的增刪改查等操作。每個模型類對應一個數據庫表,并且模型類的實例代表數據庫表中的一條記錄。
創建模型
定義模型方法
可以使用sequelize.define() 方法來創建模型,它用于定義和創建模型,其基本語法如下:
sequelize.define(modelName, attributes, options)
參數說明:
- modelName:模型的名稱。
- attributes:模型的屬性定義,一個包含列名和數據類型的對象。
- options:模型的其他選項,例如表名、時間戳等。
const { Sequelize, DataTypes } = require('sequelize');
const sequelize = new Sequelize('database', 'username', 'password');
const User = sequelize.define('User', {
id: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true,
},
username: {
type: DataTypes.STRING,
allowNull: false,
},
email: {
type: DataTypes.STRING,
allowNull: false,
unique: true,
validate: {
isEmail: true,
},
},
createdAt: {
type: DataTypes.DATE,
allowNull: false,
defaultValue: Sequelize.literal('CURRENT_TIMESTAMP'),
},
updatedAt: {
type: DataTypes.DATE,
allowNull: false,
defaultValue: Sequelize.literal('CURRENT_TIMESTAMP'),
},
}, {
tableName: 'users',
timestamps: true,
});
// 創建用戶實例
User.create({ username: 'John', email: 'john@example.com' })
.then((user) => {
console.log(user.toJSON());
})
.catch(console.error);
這里使用 sequelize.define() 方法定義了一個名為 User 的模型。模型具有 id、username、email、createdAt 和 updatedAt 等屬性。我們還指定了表名為 'users',以及啟用了時間戳屬性。
定義模型步驟
在 Sequelize 中,創建模型的步驟如下:
- 配置 Sequelize 實例連接數據庫,確定數據庫的相關信息。
- 使用 sequelize.define 方法定義模型,并指定模型的名稱、字段和其他選項。
- 通過調用模型的 sync 方法將模型同步到數據庫中。
const Sequelize = require('sequelize');
const sequelize = new Sequelize('database', 'username', 'password', {
// 配置數據庫連接信息
});
// 定義模型
const User = sequelize.define('User', {
name: Sequelize.STRING,
email: Sequelize.STRING,
age: Sequelize.INTEGER,
});
// 同步模型到數據庫
(async () => {
try {
await sequelize.sync();
console.log('模型創建成功!');
} catch (error) {
console.error('模型創建失敗:', error);
} finally {
sequelize.close(); // 關閉數據庫連接
}
})();
記得在最后關閉 Sequelize 連接,避免資源泄漏。
注意,模型創建后只需調用 sequelize.sync 方法進行同步一次即可,后續對模型的修改不會自動同步到數據庫。如果想要更新現有的模型定義,可以使用 Sequelize 提供的遷移工具或手動修改數據庫表結構。
定義模型參數
上面的例子只定義了字段的類型,其實還有很多屬性可以定義,下面來看一個例子:
const Sequelize = require('sequelize');
const sequelize = new Sequelize('database', 'username', 'password', {
// 配置數據庫連接信息
});
const User = sequelize.define('User', {
name: {
type: Sequelize.STRING,
allowNull: false,
},
email: {
type: Sequelize.STRING,
allowNull: false,
unique: true,
validate: {
isEmail: true,
},
},
age: {
type: Sequelize.INTEGER,
allowNull: false,
defaultValue: 0,
validate: {
min: 0,
},
},
});
在字段定義對象中,每個屬性表示一個字段。屬性的名稱是字段的名稱,屬性的值是字段的配置。下面來分別看看這些字段值。
type:參數類型
type 屬性用于指定模型字段的數據類型。以下是一些常見的數據類型選項:
- STRING:字符串類型。
- CHAR:字符型,允許存儲固定長度的字符串。
- TEXT:文本類型,適用于存儲大段文本數據。
- INTEGER:整數類型。
- BIGINT:大整數類型。
- FLOAT:浮點數類型。
- DOUBLE:雙精度浮點數類型。
- DECIMAL:十進制數類型。
- BOOLEAN:布爾類型。
- DATE:日期類型,不包括時間。
- TIME:時間類型,不包括日期。
- DATEONLY:僅日期類型。
- DATETIME:日期和時間類型。
- BLOB:二進制大對象類型,適用于存儲二進制數據。
- UUID:通用唯一識別碼類型。
此外,Sequelize 還支持將數據類型與修飾符結合使用,以提供更豐富的數據定義選項。例如:
- STRING(100):指定字符串類型的最大長度為 100 個字符。
- INTEGER.UNSIGNED:指定無符號整數類型。
- DECIMAL(10, 2):指定十進制數類型,并設置總共10位數,其中包含2位小數。
數字類型
在 Sequelize 中,數字類型包括以下幾種:
- INTEGER:表示整數類型。可以使用 Sequelize.INTEGER 或 Sequelize.INTEGER(n) 來定義,其中 n 是整數的位數。
- BIGINT:表示長整數類型。可以使用 Sequelize.BIGINT 或 Sequelize.BIGINT(n) 來定義,其中 n 是長整數的位數。
- FLOAT:表示單精度浮點數類型。可以使用 Sequelize.FLOAT 或 Sequelize.FLOAT(n, m) 來定義,其中 n 是總位數,m 是小數部分的位數。
- DOUBLE:表示雙精度浮點數類型。可以使用 Sequelize.DOUBLE 或 Sequelize.DOUBLE(n, m) 來定義,其中 n 是總位數,m 是小數部分的位數。
- DECIMAL:表示任意精度的十進制數類型。可以使用 Sequelize.DECIMAL 或 Sequelize.DECIMAL(n, m) 來定義,其中 n 是總位數,m 是小數部分的位數。
字符串類型
在 Sequelize 中,字符串類型有以下幾種選項可供選擇:
- STRING:表示普通的字符串類型。可以使用 Sequelize.STRING 來定義,默認最大長度為 255 個字符。
- CHAR:表示定長的字符串類型。你可以指定最大長度作為選項。可以使用 Sequelize.CHAR(length) 來定義,其中 length 是字符串的最大長度。
- TEXT:表示長文本類型。可以存儲更大長度的文本數據。可以使用 Sequelize.TEXT 來定義。
- UUID:表示 UUID 字符串類型,用于存儲全局唯一標識符。可以使用 Sequelize.UUID 來定義。
- ENUM:表示枚舉類型,用于存儲預定義的選項列表中的一個值。需要提供一個選項數組作為參數。可以使用 Sequelize.ENUM(values) 來定義,其中 values 是枚舉選項的數組。
- JSON:表示存儲 JSON 數據的字符串類型。可以使用 Sequelize.JSON 來定義。
- JSONB:表示存儲 JSONB(二進制格式的 JSON)數據的字符串類型(僅支持 PostgreSQL)。可以使用 Sequelize.JSONB 來定義。
日期類型
在 Sequelize 中,日期類型包括以下幾種:
- DATE:表示日期類型,不包含時間。可以使用 Sequelize.DATE 來定義。
- TIME:表示時間類型,不包含日期。可以使用 Sequelize.TIME 來定義。
- DATETIME:表示日期和時間類型。可以使用 Sequelize.DATE 或 Sequelize.DATETIME 來定義。
- NOW:表示當前時間。可以使用 Sequelize.NOW 來獲取當前時間的值。
- DATEONLY:表示只包含日期的類型,不包含時間。可以使用 Sequelize.DATEONLY 來定義。
- SMALLDATETIME:表示包含日期和時間的類型,時間精度較低。可以使用 Sequelize.SMALLDATETIME 來定義。
- TIMESTAMP:表示包含日期和時間的類型,時間精度高于 SMALLDATETIME。可以使用 Sequelize.TIMESTAMP 來定義。
UUID類型
在 Sequelize 中,UUID 類型用于表示一個全局唯一的標識符。Sequelize 支持以下幾種 UUID 類型:
- UUID:表示標準 UUID 字符串,長度為 36 個字符。可以使用 Sequelize.UUID 來定義。
- UUIDV1:表示基于時間戳和 MAC 地址生成的 UUID 字符串。可以使用 Sequelize.UUIDV1 來獲取該類型的默認值。
- UUIDV4:表示隨機生成的 UUID 字符串。可以使用 Sequelize.UUIDV4 來獲取該類型的默認值。
allowNull:是否可以為空
allowNull 是 Sequelize 中用于定義模型字段是否允許為空的屬性選項。
當 allowNull 設置為 true 時,表示該字段允許為空。這意味著在創建記錄或更新記錄時,可以將該字段設置為空值(null)。如果設置為 false,表示該字段不能為空。
defaultValue:默認值
defaultValue 用于定義模型字段默認值的屬性選項。
當創建記錄時,如果沒有提供該字段的值,則會使用 defaultValue 屬性定義的默認值。
primaryKey:主鍵值
primaryKey 是用于指定模型字段作為主鍵的屬性選項。
主鍵是數據庫表中的一種特殊字段,它用于唯一標識表中的每一行記錄。主鍵字段的值在整個表中必須是唯一的,并且不能為空。通過將 primaryKey 設置為 true,可以指示 Sequelize 將該字段設置為模型的主鍵。
autoIncrement:自增字段
autoIncrement 是一個用于指定模型字段是否為自增字段的屬性選項。
自增字段是一種特殊類型的主鍵,它的值會在每次插入新記錄時自動遞增。通常用于為每個新記錄分配唯一的標識符。自增字段的常見類型為整數(例如,INTEGER)。通過將 autoIncrement 設置為 true,可以指示 Sequelize 將該字段設置為自增字段。
使用自增字段可以方便地生成唯一的標識符,而無需顯式指定每個新記錄的值。數據庫在插入新記錄時會自動遞增該字段的值。這對于需要快速添加新記錄并確保主鍵唯一性的情況非常有用。
注意,autoIncrement 屬性僅對整數類型的字段有效。
unique:是否唯一
unique 用于定義模型字段是否唯一的屬性選項。
當將 unique 設置為 true 時,表示該字段的值必須在整個表中是唯一的。也就是說,在同一列中,每個記錄都必須有一個唯一的值,不能重復。
validate:校驗規則
validate 是用于定義模型字段驗證規則的屬性選項。
通過 validate 屬性,可以定義一個包含驗證規則的對象,用于驗證模型字段的值是否符合指定的條件。validate 屬性可以包含多個驗證規則,每個規則可以是一個函數或一個對象。下面是一些常見的驗證規則屬性值:
- notEmpty:確保字段的值不為空。
- len:檢查字段的長度是否在指定范圍內。可以設置一個數組,如 [min, max]。
- isEmail:驗證字段的值是否為有效的電子郵件地址。
- isUrl:驗證字段的值是否為有效的 URL。
- isAlpha:驗證字段的值是否只包含字母字符。
- isAlphanumeric:驗證字段的值是否只包含字母和數字字符。
- isNumeric:驗證字段的值是否為數字。
- isInt:驗證字段的值是否為整數。
- isFloat:驗證字段的值是否為浮點數。
- isDate:驗證字段的值是否為有效的日期。
- isAfter:驗證字段的值是否在指定日期之后。
- isBefore:驗證字段的值是否在指定日期之前。
- isIn:驗證字段的值是否在指定的數組中。
這只是一些常見的驗證規則,Sequelize 還提供了更多的內置驗證規則。此外,你還可以定義自定義的驗證函數來進行復雜的驗證邏輯。
const User = sequelize.define('User', {
username: {
type: Sequelize.STRING,
allowNull: false,
validate: {
notEmpty: true,
len: [3, 20],
isAlphanumeric: true,
},
},
email: {
type: Sequelize.STRING,
allowNull: false,
validate: {
isEmail: true,
},
},
});
comment:注釋
comment 是用于為模型字段添加注釋的屬性選項。
注釋是對字段的描述性文本,可以提供關于字段用途、含義或其他相關信息的補充說明。注釋對于理解和維護數據庫結構非常有幫助。
const User = sequelize.define('User', {
username: {
type: Sequelize.STRING,
comment: '用戶的用戶名', // 字段注釋
},
email: {
type: Sequelize.STRING,
comment: '用戶的電子郵件地址', // 字段注釋
},
});
field:字段重命名
field 是一個用于指定模型字段在數據庫中的實際名稱的屬性選項。
默認情況下,Sequelize 會將模型定義中的字段名稱直接映射到數據庫表中對應的列名。但是,有時可能希望在數據庫中使用不同的列名,這時可以使用 field 屬性來指定實際的數據庫列名。
const User = sequelize.define('User', {
firstName: {
type: Sequelize.STRING,
field: 'first_name', // 指定數據庫對應的列名
},
lastName: {
type: Sequelize.STRING,
field: 'last_name', // 指定數據庫對應的列名
},
});
在上述示例中,firstName 字段的 field 屬性設置為 first_name,lastName 字段的 field 屬性設置為 last_name。這將導致在數據庫表中創建名為 first_name和last_name 的列。
使用 field 屬性可以非常靈活地控制模型字段與數據庫列的映射關系。這在需要與遺留數據庫或特定數據庫命名約定交互的情況下非常有用。
注意,如果不指定 field 屬性,Sequelize 將默認使用與模型字段名稱相同的列名。
get 和 set:字段值計算
get
get 字段表示一個自定義的 getter 方法。它是一個通過訪問模型實例屬性來獲取計算值的函數。
使用 get 字段,可以定義一個自定義的 getter 方法,該方法會在訪問特定屬性時被調用,以便根據需要對屬性進行計算、處理或轉換。
const User = sequelize.define('User', {
firstName: {
type: Sequelize.STRING,
allowNull: false,
},
lastName: {
type: Sequelize.STRING,
allowNull: false,
},
fullName: {
type: Sequelize.VIRTUAL, // 虛擬屬性
get() {
return `${this.firstName} ${this.lastName}`;
},
},
});
const user = User.build({
firstName: 'Alice',
lastName: 'Smith',
});
console.log(user.fullName); // 輸出:Alice Smith
使用 get 字段可以方便地在訪問模型屬性時進行額外的計算或處理。它使得模型實例的屬性具有更多的靈活性和復雜性。
set
set 字段表示一個自定義的 setter 方法。它允許你在設置屬性值時執行一些自定義邏輯或轉換。
使用 set 字段,可以定義一個自定義的 setter 方法,該方法會在設置特定屬性的值時被調用,以便對該值進行處理、驗證或轉換。
const User = sequelize.define('User', {
fullName: {
type: Sequelize.STRING,
set(value) {
const names = value.split(' ');
this.setDataValue('firstName', names[0]);
this.setDataValue('lastName', names[1]);
},
},
});
const user = User.build();
user.fullName = 'Alice Smith';
console.log(user.firstName); // 輸出:Alice
console.log(user.lastName); // 輸出:Smith
當給 user.fullName 賦值時,Sequelize 將自動調用定義的 setter 方法,并進行相應的屬性設置。
使用 set 字段可以方便地在設置模型屬性值時執行自定義的邏輯或轉換操作。它使得模型屬性的賦值具有更多的靈活性和復雜性。
references:模型關聯
references 是一個模型定義中的選項,用于指定關聯關系中引用的目標模型和目標屬性。
當在 Sequelize 模型定義中使用 references 選項,它表示當前模型與另一個模型之間的關聯關系,并指定了相關聯的目標模型和目標屬性。
const User = sequelize.define('User', {
id: {
type: Sequelize.INTEGER,
primaryKey: true,
autoIncrement: true,
},
username: {
type: Sequelize.STRING,
allowNull: false,
},
});
const Post = sequelize.define('Post', {
id: {
type: Sequelize.INTEGER,
primaryKey: true,
autoIncrement: true,
},
title: {
type: Sequelize.STRING,
allowNull: false,
},
userId: {
type: Sequelize.INTEGER,
references: {
model: User, // 引用的目標模型
key: 'id', // 引用的目標屬性
},
},
});
這里定義了兩個模型:User 和 Post。在 Post 模型的定義中,使用了 references 選項來創建一個與 User 模型的關聯關系。
references 選項包含兩個屬性:
- model:指定關聯的目標模型,這里是 User。
- key:指定關聯的目標屬性,這里是 id。
這意味著 Post 模型中的 userId 屬性將引用 User 模型中的 id 屬性作為關聯。這意味著 userId 和 User 模型的 id 屬性具有相同的值。
通過使用 references 選項,Sequelize 可以根據關聯關系設置合適的數據庫約束,并幫助你在查詢中輕松處理模型之間的關聯。
onDelete:刪除關聯
onDelete 是一個定義關聯關系時可以設置的選項之一。它用于指定當關聯模型的記錄被刪除時要執行的操作。
使用 onDelete 選項,可以定義在刪除關聯模型的記錄時應該執行的操作,例如級聯刪除、設置為 null 或什么都不做等。
以下是一些常用的 onDelete 選項值及其含義:
- CASCADE:級聯刪除。當關聯模型的記錄被刪除時,與之關聯的記錄也將被刪除。
- SET NULL:設置為 null。當關聯模型的記錄被刪除時,與之關聯的記錄的外鍵值將被設置為 null。
- SET DEFAULT:設置為默認值。當關聯模型的記錄被刪除時,與之關聯的記錄的外鍵值將被設置為默認值。
- RESTRICT:限制。當關聯模型的記錄被刪除時,如果還有與之關聯的記錄存在,則會阻止刪除操作。
const User = sequelize.define('User', {
id: {
type: DataTypes.INTEGER,
primaryKey: true
}
});
const Post = sequelize.define('Post', {
id: {
type: DataTypes.INTEGER,
primaryKey: true
},
userId: {
type: DataTypes.INTEGER,
references: {
model: User,
key: 'id'
},
onDelete: 'CASCADE' // 當關聯的 User 記錄被刪除時,與之關聯的 Post 記錄也將被刪除
}
});
這里定義了一個 User 模型和一個 Post 模型。在 Post 模型的定義中,我們設置了與 User 模型的關聯,并在 userId 屬性上使用了 onDelete: 'CASCADE' 選項。這意味著當與之關聯的 User 記錄被刪除時,與之關聯的 Post 記錄也將被級聯刪除。
onUpdate:更新關聯
onUpdate 是一個定義關聯關系時可以設置的選項之一。它用于指定當關聯模型的記錄被更新時要執行的操作。
使用 onUpdate 選項,可以定義在更新關聯模型的記錄時應該執行的操作,例如級聯更新或什么都不做等。
以下是一些常用的 onUpdate 選項值及其含義:
- CASCADE:級聯更新。當關聯模型的記錄被更新時,與之關聯的記錄也將相應地進行更新。
- SET NULL:設置為 null。當關聯模型的記錄被更新時,與之關聯的記錄的外鍵值將被設置為 null。
- SET DEFAULT:設置為默認值。當關聯模型的記錄被更新時,與之關聯的記錄的外鍵值將被設置為默認值。
- RESTRICT:限制。當關聯模型的記錄被更新時,如果有其他關聯記錄存在,則會阻止更新操作。
const User = sequelize.define('User', {
id: {
type: DataTypes.INTEGER,
primaryKey: true
}
});
const Post = sequelize.define('Post', {
id: {
type: DataTypes.INTEGER,
primaryKey: true
},
userId: {
type: DataTypes.INTEGER,
references: {
model: User,
key: 'id'
},
onUpdate: 'CASCADE' // 當關聯的 User 記錄被更新時,與之關聯的 Post 記錄也將被相應地更新
}
});
這里定義了一個 User 模型和一個 Post 模型。在 Post 模型的定義中,我們設置了與 User 模型的關聯,并在 userId 屬性上使用了 onUpdate: 'CASCADE' 選項。這意味著當與之關聯的 User 記錄被更新時,與之關聯的 Post 記錄也將相應地進行級聯更新。
模型繼承
模型繼承是一種將一個模型繼承自另一個模型的機制。這使得你可以從一個已有的模型中派生出新的模型,并繼承它的屬性、方法和關聯關系,從而實現代碼重用和模型的層次結構組織。
模型繼承通過使用 sequelize.define() 方法的 options 參數來實現。在定義模型時,可以指定 options 參數中的 extend 屬性,來指定該模型繼承自哪個父模型。被繼承的父模型稱為基礎(或父)模型,而繼承的新模型稱為派生(或子)模型。
下面來看看如何在 Sequelize 中進行模型繼承:
const { Model, DataTypes } = require('sequelize');
const sequelize = new Sequelize('database', 'username', 'password');
// 定義基礎模型
const BaseModel = sequelize.define('base', {
name: {
type: DataTypes.STRING,
allowNull: false,
},
// 其他屬性...
});
// 定義派生模型,并繼承基礎模型
const DerivedModel = sequelize.define('derived', {
age: {
type: DataTypes.INTEGER,
allowNull: false,
},
// 其他屬性...
}, {
extend: BaseModel,
});
// 創建派生模型的實例
DerivedModel.create({ name: 'John', age: 25 })
.then((instance) => {
console.log(instance.toJSON());
})
.catch(console.error);
這里首先定義了一個基礎模型 BaseModel,它有一個名為 name 的屬性。然后,定義了派生模型 DerivedModel,它繼承自基礎模型,并新增了一個名為 age 的屬性。最后,我們使用派生模型的 create() 方法創建一個新的實例,并輸出其序列化后的 JSON 數據。
通過模型繼承,可以在派生模型中重用和擴展基礎模型的屬性、方法和關聯關系,從而簡化代碼的編寫和維護。這對于構建具有層次結構的數據模型非常有用,例如用戶、管理員和超級管理員之間的繼承關系。
修改模型
在 Sequelize 中,修改、刪除已有字段或新增字段的過程如下:
- 在模型定義中進行相應的更改。
- 使用 Sequelize 提供的遷移工具執行數據庫遷移操作。
過程如下:
- 修改已有字段的數據類型和屬性:
// 修改已有字段的數據類型和屬性
await sequelize.queryInterface.changeColumn('User', 'age', {
type: Sequelize.STRING,
allowNull: true,
});
- 刪除已有字段:
// 刪除已有字段
await sequelize.queryInterface.removeColumn('User', 'age');
- 新增字段:
{
// 新增字段
await sequelize.queryInterface.addColumn('User', 'gender', {
type: Sequelize.STRING,
allowNull: true,
});
這里用 Sequelize 提供的 queryInterface 對象來執行數據庫遷移操作。該對象提供了一系列方法來修改表結構。
- 對于修改已有字段,可以使用 changeColumn 方法指定要更改的模型名稱、字段名稱和新的屬性。
- 對于刪除已有字段,可以使用 removeColumn 方法指定要刪除的模型名稱和字段名稱。
- 對于新增字段,我們可以使用 addColumn 方法指定要新增字段的模型名稱、字段名稱和屬性。
在 Sequelize 中,修改模型定義并執行相應的遷移操作后,默認情況下數據庫表不會自動同步更改。你需要顯式地調用 sequelize.sync 方法來同步模型和數據庫表。以下是一個在執行遷移操作后手動調用 sequelize.sync 方法的示例代碼:
// 執行遷移操作...
// ...
// 手動同步模型和數據庫表
await sequelize.sync();
這里使用 await sequelize.sync() 方法手動同步模型和數據庫表。這將更新數據庫表結構以匹配模型定義的更改。
注意,sequelize.sync() 方法會根據模型定義生成創建、修改或刪除表的 SQL 命令,然后將其應用于數據庫。因此,請確保在生產環境中謹慎使用該方法,并提前備份重要的數據。
如果使用 Sequelize-CLI 或其他遷移工具來管理數據庫遷移,它們通常會自動處理模型與數據庫表的同步操作,你不需要手動調用 sequelize.sync() 方法。但如果你手動修改了模型定義或直接使用 queryInterface 修改數據庫表結構,則需要手動同步模型和數據庫表。
刪除模型
要刪除 Sequelize 中的模型,可以使用 sequelize.drop 方法。
以下是一個示例代碼來刪除一個名為 User 的模型:
// 刪除模型
await User.drop();
注意,刪除模型將會永久刪除數據庫表,包括其中的數據。在執行模型刪除操作之前,請確保備份重要的數據。請謹慎操作刪除模型,確保你的操作不會導致數據丟失或不可逆的更改。
在異步函數中執行刪除操作,并在完成后輸出相應的信息。最后,記得關閉 Sequelize 連接,以避免資源泄漏。
模型查詢
先來看看查詢是一些通用查詢參數。
通用參數
where:查詢條件
使用 where 方法可以添加查詢條件,它可以用于查詢語句中的各種不同部分,如 findOne 和 findAll 等。通過 where 方法可以根據指定的條件過濾數據庫中的記錄。
Op 對象是 Sequelize 中用于定義各種操作符的對象。它提供了很多常用的操作符,可以在查詢條件中使用。以下是一些常見的 Op 屬性及其對應的操作符:
- Op.eq:等于
- Op.ne:不等于
- Op.gt:大于
- Op.gte:大于等于
- Op.lt:小于
- Op.lte:小于等于
- Op.like:模糊匹配
- Op.notLike:不匹配
- Op.iLike:忽略大小寫的模糊匹配
- Op.notILike:忽略大小寫的不匹配
- Op.in:在給定數組中的值
- Op.notIn:不在給定數組中的值
- Op.between:在給定范圍內的值
- Op.notBetween:不在給定范圍內的值
等于
model.findAll({
where: {
age: 18
}
});
上述代碼會查找 age 等于 18 的所有記錄。
不等于
model.findAll({
where: {
age: {[Op.ne]: 18}
}
});
上述代碼會查找 age 不等于 18 的所有記錄。
大于
model.findAll({
where: {
age: {[Op.gt]: 18}
}
});
上述代碼會查找 age 大于 18 的所有記錄。
小于
model.findAll({
where: {
age: {[Op.lt]: 18}
}
});
上述代碼會查找 age 小于 18 的所有記錄。
大于等于
model.findAll({
where: {
age: {[Op.gte]: 18}
}
});
上述代碼會查找 age 大于等于 18 的所有記錄。
小于等于
model.findAll({
where: {
age: {[Op.lte]: 18}
}
});
上述代碼會查找 age 小于等于 18 的所有記錄。
模糊匹配
model.findAll({
where: {
name: {
[Op.like]: '%John%'
}
}
});
上述代碼會查找 name 字段中包含 "John" 的所有記錄。
也可以使用 $like 來查詢,這是 sequelize 的舊語法,建議使用新語法 [Op.like] 來查詢:
model.findAll({
where: {
name: {
$like: '%John%'
}
}
});
范圍
model.findAll({
where: {
age: {[Op.between]: [18, 30]}
}
});
上述代碼會查找 age 在 18 到 30 之間的所有記錄。
子查詢
可以使用 [Op.or] 操作符來實現查詢一個字段等于 a 或 b 的操作。
const { Op } = require('sequelize');
const users = await User.findAll({
where: {
[Op.or]: [
{ name: 'a' },
{ name: 'b' },
],
},
});
這里使用 findAll 方法查找所有名字等于 'a' 或 'b' 的用戶。其中,[Op.or] 表示 OR 連接操作符,將兩個條件拼接成 OR 條件。
注意,在實際使用時,如果需要查詢多個可能值,可以使用[Op.in]操作符,例如:
const users = await User.findAll({
where: {
name: {
[Op.in]: ['a', 'b'],
},
},
});
上述代碼將會查詢所有名字等于 'a' 或 'b' 的用戶。
include:包含關聯模型
在 Sequelize 中,可以使用關聯來定義模型之間的關系,例如一對一、一對多或多對多關系。當查詢模型時,如果希望返回與該模型關聯的其他模型的屬性,就需要使用 include 選項來包含關聯模型。可以根據需要輕松地從其他模型中獲取相關數據,而無需單獨進行額外的查詢操作。
User.findAll({
include: {
model: Post,
attributes: ['title', 'content']
}
})
.then((users) => {
// 處理查詢結果
users.forEach((user) => {
console.log('用戶名:', user.name);
console.log('用戶發布的文章:');
user.Posts.forEach((post) => {
console.log('標題:', post.title);
console.log('內容:', post.content);
});
});
})
.catch((error) => {
// 處理查詢錯誤
});
這里使用 User 模型進行查詢,通過 include 選項包含了關聯的 Post 模型。然后,在 .then 回調函數中處理查詢結果。每個用戶對象都包含了他們的相關文章數據,可以通過訪問 user.Posts 屬性來獲取關聯的文章數據。
當在主模型上執行查詢后,包含關聯模型的查詢實際上是在主模型查詢的基礎上進行的。
首先,使用主模型進行查詢,獲取與查詢條件匹配的主模型數據。然后,在查詢結果中包含的每個主模型實例上,Sequelize 將自動執行額外的查詢來獲取與之關聯的其他模型的數據。
這種查詢方式稱為延遲加載或延遲關聯。它的優點是只有在需要訪問關聯模型數據時才執行額外的查詢,避免了不必要的查詢開銷。
在上面的示例中,當調用 User.findAll() 查詢用戶時,Sequelize 會從數據庫獲取與查詢條件匹配的用戶數據。然后,當訪問 user.Posts 屬性時,Sequelize 會自動執行另一個查詢來獲取該用戶關聯的文章數據。
在查詢時包含多個關聯模型,可以通過 Sequelize 的 include 選項的不同方式來實現。下面有兩種常用的方法:
- 使用數組形式包含多個關聯模型:
User.findAll({
include: [
{ model: Profile },
{ model: Post }
]
})
.then((users) => {
// 處理查詢結果
users.forEach((user) => {
console.log('用戶名:', user.name);
console.log('用戶配置:', user.Profile);
console.log('用戶文章:', user.Posts);
});
})
.catch((error) => {
// 處理查詢錯誤
});
在上述代碼中,將要包含的關聯模型作為對象放入數組中,并將該數組作為 include 選項的值。這樣,在查詢結果中就會包含多個關聯模型的數據。
- 嵌套方式包含多個關聯模型:
User.findAll({
include: [
{
model: Profile,
include: [Category] // 在 Profile 模型中嵌套包含 Category 模型
},
{ model: Post }
]
})
.then((users) => {
// 處理查詢結果
users.forEach((user) => {
console.log('用戶名:', user.name);
console.log('用戶配置:', user.Profile);
console.log('用戶文章:', user.Posts);
console.log('用戶配置的類別:', user.Profile.Category);
});
})
.catch((error) => {
// 處理查詢錯誤
});
這里使用嵌套的方式,在其中一個關聯模型的 include 選項中,再嵌套包含另一個關聯模型。這樣可以實現更深層次的關聯查詢。
通過以上方式,可以在查詢時包含多個關聯模型,并獲取它們的數據。根據需求和模型之間的關系,可以靈活地組合和嵌套使用 include 選項來包含多個關聯模型。
注意:只有在模型定義中定義了關聯關系,才能在查詢時包含關聯模型。
attributes:返回字段
可以使用 attributes 選項指定要返回的字段。示例:attributes: ['id', 'name']。它用于控制查詢結果中包含哪些屬性或排除哪些屬性,可以接受多種形式的參數,以控制返回的屬性。
以下是幾種常見的 attributes 選項的用法:
- 字符串數組:可以傳入一個字符串數組,表示要返回的屬性名。示例:attributes: ['name', 'age'],表示查詢結果將僅包含 'name' 和 'age' 兩個字段。
- 嵌套對象:可以傳入一個嵌套對象,用于更復雜的字段控制。示例:attributes: { include: ['name'], exclude: ['age'] },表示查詢結果將包含 name 字段,并排除 age 字段。
- 聚合函數:可以使用聚合函數對屬性進行計算,并將計算結果命名為新的屬性。示例:attributes: [[sequelize.fn('SUM', sequelize.col('quantity')), 'totalQuantity']],表示查詢結果中將返回一個計算總和的聚合函數,并將計算結果命名為totalQuantity。
注意事項:
- 如果不指定 attributes 選項,默認情況下會返回所有模型的屬性;指定了 attributes 選項后,只會返回指定的屬性。
- 使用 attributes 選項時,如果要返回關聯模型的屬性,需要在關聯模型上設置 include 選項。
order:排序規則
可以使用 order 選項來指定返回結果的排序規則。示例:order: [['createdAt', 'DESC']],它表示按照 createdAt 字段進行降序排列。
在 Sequelize 中,可以通過 order 選項來指定查詢結果的排序規則。排序規則由一個二維數組表示,每個子數組包含兩個元素:排序字段和排序方式。排序字段可以是模型的屬性名或關聯模型的屬性名。排序方式可以是 'ASC'(升序)或 'DESC'(降序)。
以下是order 選項常見的用法:
- 單字段排序:可以只指定一個排序字段和排序方式。示例:order: [['fieldName', 'ASC']]。
- 多字段排序:可以指定多個排序字段和排序方式,按照指定的順序依次排序。示例:order: [['field1', 'ASC'], ['field2', 'DESC']]。
- 關聯模型排序:可以使用關聯模型的屬性進行排序。示例:order: [['RelatedModel', 'fieldName', 'ASC']]。
注意事項:
- 排序字段必須是模型或關聯模型的屬性名。
- 排序方式應為 'ASC' 或 'DESC'。
- 在查詢語句中使用多個排序條件時,將按照指定的順序依次應用這些條件。
Model.findOne({
where: {
// 查詢條件
status: 'active'
},
order: [['createdAt', 'DESC']]
})
.then((records) => {
// 處理查詢結果
})
.catch((error) => {
// 處理查詢錯誤
})
這里使用了 order 選項,通過 [['createdAt', 'DESC']] 指定了按照 createdAt 字段進行降序排列。
limit:查詢結果的數量
用于限制查詢結果返回的記錄數量,常用于分頁查詢。
Model.findAll({
limit: 10 // 返回最多 10 條記錄
})
.then((results) => {
// 處理查詢結果
})
.catch((error) => {
// 處理查詢錯誤
});
offset:查詢結果的偏移量
用于設置查詢結果的偏移量,從指定位置開始返回結果,常用于分頁查詢。這個偏移量是基于索引的,而索引是從零開始計數的。
Model.findAll({
offset: 5 // 忽略前 5 條記錄
})
.then((results) => {
// 處理查詢結果
})
.catch((error) => {
// 處理查詢錯誤
});
group:結果分組
用于對結果進行分組:按照指定的字段值進行分類歸納,將具有相同字段值的記錄放在一組中。
Model.findAll({
attributes: ['age'],
group: ['age']
})
.then((results) => {
// 處理查詢結果
results.forEach((group) => {
console.log('分組:');
group.forEach((record) => {
console.log('記錄:', record);
});
});
})
.catch((error) => {
// 處理查詢錯誤
});
這里使用 group 選項對 age 字段進行分組。查詢結果 results 是一個數組,其中每個元素代表一個分組。對于每個分組,可以遍歷內層數組 group,其中的每個元素代表該分組中的一條記錄。
distinct:結果去重
當設置 distinct: true 時,查詢結果將會返回去重后的記錄。這在某些情況下非常有用,例如獲取一個字段的唯一值列表或者按照某個字段進行分組統計時。
這里使用 distinct: true 設置查詢結果為去重模式,并指定了要查詢的字段為 name。查詢結果將只包含去重后的姓名列表。
例如,假設有一個名為 User 的模型,并且希望獲取所有不重復的用戶名:
const users = await User.findAll({
attributes: ['name'],
distinct: true
});
這里通過設置 distinct: true 來確保只返回不重復的用戶名。查詢結果將只包含唯一的、不重復的用戶名。
注意,distinct 選項必須與指定的查詢字段一起使用,確保只對指定的字段進行去重操作。
findOne:查詢第一條
查詢符合條件的第一條記錄。
Model.findOne({
where: {
// 查詢條件
id: 1
}
})
.then((record) => {
if (record) {
console.log('查詢到的記錄:', record.get({ plain: true }));
} else {
console.log('未找到符合條件的記錄');
}
})
.catch((error) => {
// 處理查詢錯誤
});
這個方法的返回值是一個 Sequelize Model 對象,其中包含與記錄相關聯的屬性、方法和關系。它具有以下特性:
- 屬性訪問:可以通過屬性名直接訪問記錄的字段值,例如 record.fieldName。
- 數據獲取:可以使用 .get() 方法獲取包含所有字段的對象形式的記錄數據,例如 record.get(),其用法如下。
record.get():返回一個包含所有字段的對象,其中字段名作為鍵,字段值作為值。這個對象是 Sequelize 模型實例,包含與記錄相關聯的屬性和方法。
record.get({ plain: true }):返回一個純對象,只包含記錄的原始字段和值,不包含與 Sequelize 相關的屬性和方法。
獲取指定字段的值:可以傳遞一個或多個字段名作為參數,獲取特定字段的值。示例:record.get('fieldName') 或 record.get('field1', 'field2')。
排除指定字段:可以使用 { exclude: ['fieldName'] } 選項來排除指定的字段,獲取除這些字段外的其他字段。示例:record.get({ exclude: ['fieldName'] })。
只獲取指定字段:可以使用 { attributes: ['fieldName'] } 選項來只獲取指定的字段。示例:record.get({ attributes: ['fieldName'] })。
Model.findOne({
where: {
// 查詢條件
id: 1
}
})
.then((record) => {
if (record) {
const fieldValue = record.get('fieldName');
console.log('字段值:', fieldValue);
const excludedData = record.get({ exclude: ['field1', 'field2'] });
console.log('排除字段后的數據:', excludedData);
const selectedData = record.get({ attributes: ['field1', 'field2'] });
console.log('只包含指定字段的數據:', selectedData);
} else {
console.log('未找到符合條件的記錄');
}
})
.catch((error) => {
// 處理查詢錯誤
});
注意,Model.findOne 方法只返回滿足查詢條件的第一條記錄。如果沒有符合條件的記錄,則返回 null。
另外,distinct: true 在某些數據庫管理系統中可能會導致性能下降,因為它需要進行更多的計算來實現去重。所以在使用 distinct: true 時,要謹慎考慮其對性能的影響。
findAll:查詢全部
sequelize.findAll() 用于從數據庫中檢索所有匹配給定條件的記錄。它的語法如下:
Model.findAll({
attributes: [], // 要選擇的屬性列表,默認為所有屬性
where: {}, // 過濾條件
include: [], // 關聯模型
order: [], // 排序規則
limit: 0, // 返回的最大記錄數,默認為0(返回所有記錄)
offset: 0, // 結果集的起始偏移量,默認為0
});
參數說明:
- attributes:指定要選擇的屬性列表,如果為空,則返回所有屬性。
- where:指定過濾條件,可以使用各種條件運算符(如等于、不等于、大于、小于等)來篩選記錄。
- include:指定要關聯的其他模型,可以進行關聯查詢。
- order:指定結果集的排序規則。
- limit:指定要返回的最大記錄數,默認為0,表示返回所有符合條件的記錄。
- offset:指定結果集的起始偏移量,默認為0。
這個方法將返回一個Promise,當查詢成功時,Promise將解析為包含所有符合條件的記錄的數組。以下是一個示例:
Model.findAll({
where: {
// 查詢條件
status: 'active'
}
})
.then((records) => {
if (records.length > 0) {
console.log('查詢到的記錄數:', records.length);
records.forEach((record) => {
const data = record.get();
console.log('記錄數據:', data);
});
} else {
console.log('未找到符合條件的記錄');
}
})
.catch((error) => {
// 處理查詢錯誤
});
注意,如果沒有查詢到符合條件的記錄,返回的數組將為空。
findByPk:根據主鍵值查詢
根據主鍵值查詢記錄,它的語法如下:
Model.findByPk(id, options);
參數說明:
- id:要查詢的記錄的主鍵值。
- options:可選參數,用于指定進一步的配置,比如關聯模型等。
下面來看一個例子,通過主鍵值來獲取特定的用戶記錄:
const user = await User.findByPk(1);
console.log(user);
上述代碼將查詢主鍵值為 1 的用戶記錄,并將結果保存在 user 變量中。如果找到匹配的記錄,則 user 將是一個包含該記錄的對象。否則,user 將是 null。
如果要通過主鍵值獲取多個記錄,可以傳入一個數組作為 id 參數,如:
const users = await User.findByPk([1, 2, 3]);
console.log(users);
上述代碼將查詢主鍵值為 1、2 和 3 的用戶記錄,并將結果保存在 users 變量中,它將是一個包含這些記錄的數組。
findByPk 也可以與其他查詢配置選項一起使用,例如關聯模型、選擇屬性等。可以在 options 參數中指定這些額外的配置選項。
注意:findByPk 方法返回一個 Promise,在查詢成功時解析為匹配的記錄(或記錄數組),在查詢失敗時拒絕為錯誤對象。因此,需要使用 await 或 .then() 來處理查詢結果或捕獲錯誤。
在 Sequelize 中,主鍵值是指用于唯一標識數據庫表中每個記錄的列或屬性。主鍵值在表中具有唯一性,沒有重復的值,且不能為空。在 Sequelize 模型定義中,可以通過 primaryKey: true 來將某個屬性指定為主鍵。例如:
const User = sequelize.define('User', {
id: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true
},
name: DataTypes.STRING,
email: DataTypes.STRING
});
在上述例子中,id 屬性被指定為主鍵。它的類型為整數(INTEGER),并且設置了 primaryKey: true 表示該屬性是主鍵。此外,還可以使用 autoIncrement: true 來指定該主鍵自動增長,以便在插入新記錄時自動生成唯一的主鍵值。
當使用 findByPk、update、destroy 等方法時,通常會使用主鍵值來準確定位要操作的記錄。通過提供正確的主鍵值,Sequelize 可以根據主鍵來查詢、更新或刪除相應的記錄。
findOrCreate:查詢或創建
findOrCreate 用于根據指定條件查找數據庫中的記錄,如果找到匹配的記錄,則返回該記錄;如果找不到匹配的記錄,則創建一個新的記錄并返回。它的語法如下:
Model.findOrCreate({
where: { ... },
defaults: { ... },
...
});
參數說明:
- where:包含查找條件的對象,用于指定要匹配的屬性和值。
- defaults:包含要創建新記錄時的默認值的對象。
- ...:其他可選參數,用于進一步配置查詢。
使用 findOrCreate 方法時,Sequelize 首先根據 where 條件嘗試在數據庫中查找符合條件的記錄。如果找到匹配的記錄,則返回該記錄作為結果。
如果沒有找到匹配的記錄,則使用 defaults 指定的默認值創建一個新的記錄,并返回該新記錄作為結果。默認值將應用于新創建的記錄的屬性。
例如,假設有一個名為 User 的模型表示用戶表,其中 email 是唯一的:
const User = sequelize.define('User', {
name: DataTypes.STRING,
email: {
type: DataTypes.STRING,
unique: true
}
});
現在想根據郵箱查找用戶記錄,如果找到則返回該記錄,如果找不到則創建一個新用戶記錄。可以使用 findOrCreate 方法:
const [user, created] = await User.findOrCreate({
where: { email: 'example@example.com' },
defaults: { name: 'John Doe' }
});
console.log(user); // 匹配的記錄或新創建的記錄
console.log(created); // 表示是否新創建了記錄的布爾值
上述代碼將根據指定的郵箱查找用戶記錄,如果找到匹配的記錄,則返回該記錄。如果沒有找到匹配的記錄,則創建一個新的記錄,并返回新創建的記錄。
findOrCreate 方法返回一個包含兩個元素的數組:第一個元素是匹配的記錄(已存在或新創建),第二個元素是一個布爾值,表示是否新創建了記錄。
如果有多個符合條件的記錄,findOrCreate 方法僅返回匹配的第一個記錄。它不會返回所有符合條件的記錄。
findAndCountAll:查詢記錄和數量
findAndCountAll 用于查找滿足指定條件的所有記錄,并返回滿足條件的記錄數組和記錄總數。它的語法如下:
Model.findAndCountAll({
where: { ... },
include: [ ... ],
offset: ...,
limit: ...,
order: [...],
...
});
參數說明:
- where:包含查找條件的對象,用于指定要匹配的屬性和值。
- include:指定關聯模型,用于在查詢中包含關聯的數據。
- offset:指定查詢的偏移量,用于分頁。
- limit:指定查詢的限制數量,用于分頁。
- order:指定查詢結果的排序順序。
- ...:其他可選參數,用于進一步配置查詢。
使用 findAndCountAll 方法時,Sequelize 將根據指定的條件在數據庫中查找符合條件的所有記錄,并同時返回滿足條件的記錄數組和記錄總數。
const { count, rows } = await User.findAndCountAll({
where: { age: 25 },
include: [Post],
offset: 0,
limit: 10,
order: [['createdAt', 'DESC']]
});
console.log(count); // 符合條件的記錄總數
console.log(rows); // 符合條件的記錄數組
在上述代碼中,findAndCountAll 方法將根據年齡為 25 的條件在數據庫中查找用戶記錄,并返回滿足條件的記錄總數和記錄數組。include 參數用于指定要關聯的 Post 模型。
findAndCountAll 方法返回的結果是一個包含 count 和 rows 屬性的對象。count 表示符合條件的記錄總數,rows 表示符合條件的記錄數組。
使用 findAndCountAll 方法可以方便地獲取滿足條件的記錄總數以及相應的記錄數組,用于實現分頁和其他結果統計的需求。
count:查詢數量
可以使用 count 方法來獲取滿足指定條件的記錄數。它的語法如下:
Model.count({
where: { ... },
...
});
參數說明:
- where:包含查找條件的對象,用于指定要匹配的屬性和值。
- ...:其他可選參數,用于進一步配置查詢。
使用 count 方法時,Sequelize 將根據指定的條件在數據庫中計算符合條件的記錄數,并返回該記錄數。
const count = await User.count({
where: { age: 25 }
});
console.log(count); // 符合條件的記錄數
在上述代碼中,count 方法將根據年齡為 25 的條件在數據庫中計算符合條件的用戶記錄數,并將其返回。該方法返回的結果將是一個表示符合條件的記錄數的整數值。
通過使用 count 方法,可以方便地獲取滿足條件的記錄數,用于進行結果統計、分頁計算或其他相關處理。
min, max, sum:查詢最值
可以使用 min、max 和 sum 方法來進行最小值、最大值和求和計算。
這些方法可以通過調用模型的靜態方法來實現,具體語法如下:
- min 方法用于計算指定屬性列的最小值:
Model.min('column', {
where: { ... },
...
});
- max 方法用于計算指定屬性列的最大值:
Model.max('column', {
where: { ... },
...
});
- sum 方法用于計算指定屬性列的總和:
Model.sum('column', {
where: { ... },
...
});
參數說明:
- 'column':要進行計算的屬性列的名稱。
- where:包含查找條件的對象,用于指定要匹配的屬性和值。
- ...:其他可選參數,用于進一步配置查詢。
const minValue = await Model.min('column', {
where: { ... }
});
const maxValue = await Model.max('column', {
where: { ... }
});
const sumValue = await Model.sum('column', {
where: { ... }
});
console.log(minValue); // 最小值
console.log(maxValue); // 最大值
console.log(sumValue); // 總和
注意,這些方法將返回一個 Promise 對象,需要使用 await 或 .then() 來獲取計算結果。
create:創建數據
create() 方法用于在數據庫中創建一個新的記錄。它是 Sequelize 模型的一個實例方法,可以通過模型對象調用。
const newUser = await User.create({
name: 'John Doe',
email: 'john.doe@example.com',
age: 25,
});
使用 User.create() 方法創建一個名為 User 的新記錄。通過傳遞一個包含屬性和值的對象參數,指定要創建的記錄的字段值。調用 create()方法會將新記錄插入到與模型關聯的數據庫表中,并返回一個表示新記錄的模型實例。
注意,create() 方法返回的是一個 Promise 對象,因此可以使用 await 關鍵字來等待創建操作的結果。如果創建成功,將返回包含新記錄數據的模型實例;如果創建失敗,將拋出一個異常。
create() 方法可以用于創建單個記錄,也可以用于批量創建多條記錄。如果想要批量創建多條記錄,可以將一個包含多個對象的數組傳遞給 create() 方法。
const newUsers = await User.create([
{
name: 'John Doe',
email: 'john.doe@example.com',
age: 25,
},
{
name: 'Jane Smith',
email: 'jane.smith@example.com',
age: 30,
},
]);
bulkCreate:批量創建數據
要批量添加數據,可以使用 Model.bulkCreate() 方法。bulkCreate() 方法接受一個數組作為參數,每個數組元素都表示要創建的記錄。
const newUsers = await User.bulkCreate([
{
name: 'John Doe',
email: 'john.doe@example.com',
age: 25,
},
{
name: 'Jane Smith',
email: 'jane.smith@example.com',
age: 30,
},
// 可以繼續添加更多對象...
]);
這里定義了一個 users 數組,其中包含要添加到數據庫的多個對象,每個對象表示一條記錄。然后,調用 User.bulkCreate() 方法,并傳遞 users 數組作為參數,以批量添加這些記錄。
bulkCreate() 方法將會將數組中的每個對象插入到與模型關聯的數據庫表中,并返回一個包含新記錄的模型實例數組。可以根據實際需求在 users 數組中添加任意數量的對象,以批量添加相應數量的記錄。
bulkCreate() 和 create() 方法都可以用于創建多條數據,但它們之間有一些區別:
- 性能差異:
- create() 方法在循環中逐個創建記錄,并執行多個數據庫查詢操作。這意味著對于大量數據的批量創建,性能可能較低。
- bulkCreate() 方法會將所有記錄作為一個事務一次性插入數據庫,減少了數據庫查詢操作的次數,因此在處理大量數據時可以更高效。
- 錯誤處理:
- create() 方法是可回滾的,即如果在循環中創建多個記錄時發生錯誤,可以選擇回滾已創建的記錄。
- bulkCreate() 方法默認情況下是不可回滾的,即如果在批量插入過程中發生錯誤,已插入的記錄將被保留。但你可以通過設置 individualHooks: true 選項來啟用回滾功能。
- 返回值:
- create() 方法在成功創建每條記錄后,返回一個表示該記錄的模型實例。
- bulkCreate() 方法在成功插入所有記錄后,返回一個包含所有新記錄的模型實例數組。
綜上所述,對于需要創建大量數據的情況,推薦使用 bulkCreate() 方法,以獲得更好的性能。但在某些情況下,例如需要在每次創建記錄時進行自定義操作或錯誤處理時,可以選擇使用 create() 方法。
update:更新數據
可以使用 update 方法來更新數據庫中的記錄。它的語法如下:
Model.update(values, {
where: { ... },
...
});
參數說明:
- values:一個包含要更新的屬性和值的對象。
- where:一個包含更新條件的對象,用于指定要匹配的屬性和值。
- ...:其他可選參數,用于進一步配置更新。
使用 update 方法時,Sequelize 將根據指定的條件在數據庫中查找符合條件的記錄,并將相應的屬性更新為指定的新值。
const result = await User.update(
{ age: 30, status: 'active' },
{
where: { id: 1 }
}
);
console.log(result); // 更新結果
在上述代碼中,update 方法將會將 id 屬性為 1 的用戶記錄的 age 和 status 屬性更新為新的值。
注意,update 方法返回一個表示更新結果的數組。該數組的第一個元素表示更新的行數,第二個元素表示影響的行數。
const updatedRows = result[0];
const affectedRows = result[1];
console.log(updatedRows); // 更新的行數
console.log(affectedRows); // 影響的行數
通過使用 update 方法,可以方便地更新滿足條件的記錄,并可以靈活配置要更新的屬性和值。
注意,update 方法只能更新單條記錄。如果想要更新多條數據,可以借助 Promise.all 來實現:
// 查找需要更新的數據
const usersToUpdate = await User.findAll({ where: { status: 'active' } });
// 更新數據
await Promise.all(usersToUpdate.map(user => {
return user.update(
{ status: 'inactive' } // 更新的字段和值
);
}));
destroy:刪除數據
在 Sequelize 中,可以使用 destroy 方法來刪除數據庫中的記錄。它的語法如下:
Model.destroy({
where: { ... },
...
});
參數說明:
- where:包含刪除條件的對象,用于指定要匹配的屬性和值。
- ...:其他可選參數,用于進一步配置刪除操作。
使用 destroy 方法時,Sequelize 將根據指定的條件在數據庫中查找符合條件的記錄,并將其從數據庫中刪除。
const result = await User.destroy({
where: { id: 1 }
});
console.log(result); // 刪除結果
在上述代碼中,destroy 方法將會刪除數據庫中 id 屬性為 1 的用戶記錄。該方法返回一個表示刪除結果的整數值。該值表示成功刪除的記錄數。
destroy 方法可以刪除滿足多個條件的記錄,從而批量刪除數據庫中的多個值。
const result = await User.destroy({
where: {
age: { [Op.gt]: 30 }, // 年齡大于30
status: 'inactive' // 狀態為inactive
}
});
console.log(result); // 刪除結果
上述代碼將會刪除數據庫中年齡大于30且狀態為inactive的用戶記錄。
模型聚合
模型聚合指的是使用 Sequelize 模型來執行數據庫查詢,并對查詢結果進行聚合操作。通過使用 Sequelize 模型的聚合功能,你可以靈活地執行各種統計和計算操作,并從數據庫中獲取所需的聚合結果。
模型聚合通常用于在查詢中應用聚合函數,以獲取關于數據集的匯總信息。聚合函數可以是內置的數據庫函數,也可以是自定義的函數。常見的聚合函數包括 SUM、COUNT、AVG、MAX、MIN 等。
假設有一個 Product 模型,它表示產品表。每個產品都有一個 price 字段,表示產品的價格。現在,想計算所有產品的平均價格。可以使用 Sequelize 的模型聚合功能來實現:
const { fn, col } = require('sequelize');
const result = await Product.findOne({
attributes: [
[fn('AVG', col('price')), 'avgPrice']
]
});
這里使用 Product.findOne 查詢單個產品,并使用 attributes 參數指定要選擇的屬性列。我們使用 sequelize.fn 和 sequelize.col 創建了一個新的屬性列,將其命名為 avgPrice,并應用了 AVG 聚合函數來計算價格的平均值。查詢結果將包含產品價格的平均值,以及對應的屬性名稱。
注意,通過使用 sequelize.fn 和 sequelize.col,可以在查詢結果中創建一個虛擬的屬性列,用于存儲聚合函數計算得出的值(例如平均值、總和等)。這個虛擬字段只存在于查詢結果中,而不會對數據庫中的數據產生影響。換句話說,當執行查詢并獲取結果時,每條結果將包含從數據庫中選擇的實際屬性列以及計算得出的虛擬屬性列(例如 avgPrice)。這些虛擬屬性僅在查詢結果中可見,不會直接影響數據庫中的數據。
sequelize.fn
sequelize.fn 是 Sequelize 提供的一個函數,用于生成聚合函數的 SQL 片段。使用 sequelize.fn,可以在查詢中使用所有支持的聚合函數(如 COUNT、SUM、AVG、MIN、MAX 等)。
sequelize.fn 的語法如下:
sequelize.fn(functionName, args)
其中,functionName 是要調用的聚合函數名稱,如 COUNT、SUM、AVG、MIN、MAX 等;args 是可選的函數參數,可以是列名稱或常量值。
sequelize.fn 可以與 sequelize.col 一起使用,用于生成復雜的 SQL 片段和查詢語句。它還可以與 where、group、having、order 等查詢選項一起使用。
sequelize.col
sequelize.col 用于生成對數據庫表中列的引用,使用 sequelize.col可以在查詢中引用特定的列。
sequelize.col 的語法如下:
sequelize.col(columnName)
其中,columnName 是要引用的列名稱。它可以是字符串形式的列名,也可以是一個包含表名和列名的數組。
下面使用 sequelize.col 引用 products 表中的 price 列:
const { col } = require('sequelize');
Product.findAll({
attributes: [
[col('price'), 'productPrice']
]
});
這里使用了 col 函數來生成一個對 price 列的引用,并將其映射到一個名為 productPrice 的屬性上。這樣,查詢結果中就會包含一個帶有別名的新屬性,它的值是 price 列的值。
屬性別名
[col('price'), 'productPrice'] 用于在查詢中定義屬性別名。它使用了數組的形式來表示一個屬性,并包含兩個元素:引用列的表達式和屬性別名。在這個例子中,col('price') 是一個 sequelize.col 函數調用,表示對 price 列的引用。'productPrice' 是一個字符串,表示希望將 price 列的值映射到一個名為 productPrice 的屬性上。這樣,返回的結果將會包含一個名為 productPrice 的屬性,其中的值是對應的 price 列的值。
選擇所有列
col('*') 表示引用表中的所有列。通常,在 Sequelize 中,我們可以在 attributes 數組中使用它來選擇查詢結果中要返回的列。
const { col } = require('sequelize');
Product.findAll({
attributes: [
col('*')
]
});
這里使用 col('*') 來引用所有列。這意味著查詢結果將包含表中的每個列。
請注意,使用 col('*') 將返回表中的所有列,包括主鍵、外鍵和其他所有列。如果只想選擇特定的列,可以將列名以字符串的形式傳遞給 col 函數,如 col('columnName')。
sequelize.literal
在 Sequelize 中,可以使用 sequelize.literal 方法來自定義聚合函數或任何其他數據庫原生函數。
sequelize.literal 允許在查詢中添加原始的 SQL 代碼,包括自定義的聚合函數。可以通過將 SQL 代碼作為字符串傳遞給 sequelize.literal 來實現。
下面來使用 sequelize.literal 自定義一個名為 customCount 的聚合函數:
const { literal } = require('sequelize');
Product.findAll({
attributes: [
[literal('COUNT(*) + 1'), 'customCount']
]
});
這里使用了 literal 函數來生成一個原始的 SQL 表達式 COUNT(*) + 1,并將其映射到一個名為 customCount 的屬性上。
請注意,使用 sequelize.literal 時需小心確保代碼的安全性和正確性,以避免潛在的風險和錯誤。請謹慎使用,并確保仔細檢查和測試自定義函數的邏輯。
模型關聯
在 Sequelize 中,模型關聯是指在不同表之間建立起的關系,使得可以通過一個模型對象訪問到與其相關聯的其他模型對象的數據。
Sequelize 支持多種類型的模型關聯,包括一對一(One-to-One)、一對多(One-to-Many)和多對多(Many-to-Many)等。通過定義模型之間的關聯關系,我們可以方便地執行跨表查詢、創建、更新以及刪除操作,而無需手動編寫復雜的 JOIN 查詢。
在 Sequelize 中,定義模型關聯的方法有以下幾種:
- hasOne:定義一對一的關聯關系。該方法通常用于聲明一個模型擁有唯一的關聯模型。
- hasMany:定義一對多的關聯關系。該方法通常用于聲明一個模型擁有多個關聯模型。
- belongsToMany:定義多對多的關聯關系。該方法用于建立兩個模型之間的多對多關聯關系,需要通過一個中間模型來實現。
- belongsTo:定義一對一或一對多的關聯關系。該方法通常用于聲明一個模型屬于另一個模型,也可以用于建立模型之間的一對多關聯關系。
例如,假設有兩個模型:User(用戶)和Post(帖子)。一個用戶可以擁有多篇帖子,而一篇帖子只能屬于一個用戶。在這種情況下,我們可以通過一對多的關系來建立模型關聯。
可以通過在模型定義中使用 hasMany 和 belongsTo 方法來定義一對多的關聯關系。下面是一個示例:
// User 模型定義
const User = sequelize.define('User', {
// ...其他屬性
});
// Post 模型定義
const Post = sequelize.define('Post', {
// ...其他屬性
});
// 建立一對多關聯
User.hasMany(Post, { foreignKey: 'userId' });
Post.belongsTo(User, { foreignKey: 'userId' });
在上述示例中,User.hasMany(Post) 表示用戶模型擁有多個帖子,Post.belongsTo(User) 表示帖子模型屬于一個用戶。通過指定外鍵 userId,Sequelize 將根據該外鍵進行關聯查詢。
通過建立模型關聯,可以使用框架提供的方法來執行聯表查詢,例如:
// 查詢用戶及其所有帖子
const user = await User.findByPk(userId, { include: Post });
// 查詢帖子及其所屬用戶
const posts = await Post.findAll({ include: User });
這樣就可以方便地在相關聯的模型之間進行數據查詢和操作。