Bài trước: Web back-end (22) - Tạo cơ sở dữ liệu bằng Sequelize
-----
23. Tạo các bảng và mối quan hệ
23.1 Tạo các bảng có mối quan hệ 1-n
Vào cửa sổ dòng lệnh, tắt web server, nhập vào đoạn mã sau để tạo model cho bảng Images:
E:\TeoShop>sequelize model:create --name Image --attributes name:string,imagePath:string
Sequelize CLI [Node: 22.14.0,
CLI: 6.6.2, ORM: 6.37.7]
New model was created at
E:\TeoShop\models\image.js .
New migration was created at
E:\TeoShop\migrations\20250506035103-create-image.js .
Nhập vào đoạn mã sau để tạo model cho bảng Brands:
E:\TeoShop>sequelize model:create --name Brand --attributes name:string,imagePath:string
Sequelize CLI [Node: 22.14.0,
CLI: 6.6.2, ORM: 6.37.7]
New model was created at
E:\TeoShop\models\brand.js .
New migration was created at
E:\TeoShop\migrations\20250506035329-create-brand.js .
Tạo mối quan hệ 1-n
Mối quan hệ giữa 2 bảng Products và Images là 1-n, nghĩa là một sản phẩm (product) sẽ có nhiều hình ảnh (image).
Vào tập tin models\product.js, thêm đoạn mã sau:
[models\product.js]
…
*/
static
associate(models) {
//
define association here
Product.hasMany(models.Image, { foreignKey: 'productId' });
}
}
Product.init({
…
Hiểu đoạn mã nguồn là: một product thì có nhiều (hasMany) image, khóa ngoại trong bảng Images sẽ có tên là productId.
Vào tập tin models\image.js, thêm vào đoạn mã sau:
[models\image.js]
…
*/
static
associate(models) {
//
define association here
Image.belongsTo(models.Product, { foreignKey:'productId'});
}
}
Image.init({
…
Hiểu đoạn mã nguồn là: một image thuộc về (belongs to) một product, thông qua khóa ngoại productId.
Tương tự, mối quan hệ giữa 2 bảng Brands và Products là 1-n, nghĩa là một thương hiệu (brand) sẽ có nhiều sản phẩm (product).
Vào tập tin models\brand.js, thêm đoạn mã sau:
[models\brand.js]
…
*/
static
associate(models) {
//
define association here
Brand.hasMany(models.Product, { foreignKey:'brandId' });
}
}
Brand.init({
…
Hiểu đoạn mã nguồn là: một brand có nhiều (hasMany) product, thông qua khóa ngoại brandId.
Vào tập tin models\product.js, thêm đoạn mã sau:
[models\product.js]
…
static
associate(models) {
//
define association here
Product.hasMany(models.Image,
{ foreignKey: 'productId'
});
Product.belongsTo(models.Brand, { foreignKey:'brandId' } );
}
…
Hiểu đoạn mã nguồn là: một product thuộc về (belongsTo) một brand, thông qua khóa ngoại brandId.
Để cập nhật các khai báo về mối quan hệ 1-n vừa khai báo ở trên vào cơ sở dữ liệu, chúng ta cần thực hiện các bước sau:
- Lưu lại mã nguồn của các tập tin vừa được thêm mã nguồn.
- Mở pgAdmin, xóa các bảng liên quan (Products).
- Khởi chạy lại web server.
- Mở trình duyệt web, gõ lại lệnh /createTables (http://localhost:9000/createTables).
- Nếu lệnh /createTables chạy thành công, bạn sẽ thấy dòng thông báo “tables created” trên trình duyệt
- Mở lại cơ sở dữ liệu trong pgAdmin sẽ thấy 3 bảng xuất hiện, trong mỗi bảng sẽ có thêm trường khóa ngoại (ví dụ, trong bảng Products sẽ là brandId; trong bảng Images sẽ là productId). Các trường createdAt và updateAt trong mỗi bảng cũng được tạo tự động. Trong mỗi bảng, bạn vào mục Constraints để xem các khóa ngoại đã được tạo ra (ví dụ Images_productId_fkey).
23.2 Tạo các bảng có mối quan hệ n-n
Quay trở lại các bảng dữ liệu của ứng dụng TeoShop, chúng ta có bảng Tags, dùng để lưu các thẻ (từ khóa, nhãn); thẻ này sẽ được gắn vào sản phẩm (product). Những thẻ này giúp mô tả các đặc điểm, phong cách, hoặc thuộc tính nổi bật của sản phẩm, từ đó hỗ trợ việc tìm kiếm, lọc và khám phá sản phẩm một cách hiệu quả hơn cho cả người quản lý và khách hàng.
Một product có thể gắn nhiều tag; một tag có thể gắn cho nhiều product. Do vậy, mối quan hệ giữa bảng Products và Tags là n - n (nhiều - nhiều).
Vào cửa sổ dòng lệnh, tắt web server, nhập vào đoạn mã sau để tạo model cho bảng Tags:
E:\TeoShop>sequelize model:create --name Tag --attributes name:string
Sequelize CLI [Node: 22.14.0,
CLI: 6.6.2, ORM: 6.37.7]
New model was created at
E:\TeoShop\models\tag.js .
New migration was created at
E:\TeoShop\migrations\20250506091413-create-tag.js .
Nhập tiếp đoạn mã sau để tạo model cho bảng ProductTags (vì bảng này chỉ có 2 thuộc tính là khóa ngoại, nên sẽ không cần tùy chọn --attributes, nhưng thiếu tùy chọn này lệnh sẽ bị lỗi, vì vậy chúng ta cứ thêm tùy chọn --attributes name:string rồi sẽ xóa sau):
E:\TeoShop>sequelize
model:create --name ProductTag --attributes name:string
Sequelize CLI [Node: 22.14.0,
CLI: 6.6.2, ORM: 6.37.7]
New model was created at E:\TeoShop\models\producttag.js
.
New migration was created at
E:\TeoShop\migrations\20250506091721-create-product-tag.js .
Để định nghĩa mối quan hệ nhiều-nhiều giữa bảng Products và Tags, chúng ta cần định nghĩa trên 3 model, gồm: product.js, tag.js và producttag.js.
Vào tập tin models\tag.js, thêm đoạn mã sau:
[models\tag.js]
…
*/
static associate(models) {
// define association here
Tag.belongsToMany(models.Product,
{ through: 'ProductTag',
foreignKey: 'tagId',
otherKey: 'productId'
});
}
}
Tag.init({
…
Hiểu đoạn mã nguồn là: một tag thuộc về nhiều (belongsToMany) product, được thể hiện trong bảng ProductTags, với khóa chính được tạo ra từ 2 khóa ngoại là tagId và productId.
Tương tự, vào tập tin models\product.js, thêm vào đoạn mã sau:
[models\product.js]
…
Product.hasMany(models.Image,
{ foreignKey: 'productId'
});
Product.belongsTo(models.Brand,
{ foreignKey:'brandId'
} );
Product.belongsToMany(models.Tag, { through: 'ProductTag', foreignKey: 'productId', otherKey: 'tagId' });
}
}
...
Tương tự, vào tập tin models\producttag.js, thêm vào đoạn mã sau:
[models\producttag.js]
…
static associate(models) {
// define association here
ProductTag.belongsTo(models.Product, {
foreignKey: 'productId' });
ProductTag.belongsTo(models.Tag,
{ foreignKey: 'tagId' });
}
}
ProductTag.init({
…
Chúng ta cũng xóa bỏ dòng tô đậm (tạo cột name: name:
DataTypes.STRING) trong models\producttag.js
[models\producttag.js]
}
ProductTag.init({
name: DataTypes.STRING
},
{
sequelize,
modelName:
'ProductTag',
});
return
ProductTag;
Do chúng ta không chỉnh sửa các cột của bảng Products, nên chúng ta không cần xóa bảng Products, mà chỉ cần chạy lệnh \createTables để tạo bảng Tags và ProductTags từ model tag.js và producttag.js.
- Lưu lại mã nguồn các model: product.js, tag.js và producttag.js.
- Khởi chạy lại web server
- Mở trình duyệt, nhập vào đường dẫn: http://localhost:9000/createTables
- Nếu việc tạo bảng thành công, trình duyệt sẽ có dòng chữ “tables created”
- Vào pgAdmin sẽ thấy có bảng Tags, ProductTags được tạo ra.
Bạn có thể xem Sơ đồ quan hệ thực thể (ERD - Entity Relationship Diagram) của cơ sở dữ liệu teoshopDB. Ví dụ trong pgAdmin, chuột phải vào teoshopDB > chọn ERD For Database.
Xem hình minh họa ERD.
23.3 Bài tập
Bài tập 23.1 Tạo các bảng và thiết lập các quan hệ giữa các bảng.
-----
Cập nhật: 7/5/2025
Bài sau: