Sequelize ORM + PostgreSQL — CRUD
Sequelize nima va nima muammoni hal qiladi?
Ma'lumotlar bazasi bilan ishlashda odatda SQL yoziladi:
SELECT * FROM users WHERE id = 1;
INSERT INTO users (name, email) VALUES ('Ali', 'ali@example.com');
UPDATE users SET name = 'Vali' WHERE id = 1;
DELETE FROM users WHERE id = 1;
Bu ishlaydi — lekin muammolar bor:
- Xavfsizlik: SQL injection — foydalanuvchi kiritgan ma'lumot to'g'ridan-to'g'ri so'rovga tushsa, hacker bazani buzishi mumkin
- Takroriylik: Har safar bir xil
SELECT,INSERTkodni yozish - Tip xavfsizligi: TypeScript bilan SQL string — hech qanday tip tekshiruvi yo'q
- Ko'chma emas: MySQL dan PostgreSQL ga o'tish — barcha so'rovlarni qayta yozish
ORM (Object-Relational Mapping) — bu muammolarni hal qiladi. SQL o'rniga JavaScript/TypeScript ob'ektlari bilan ishlaysiz. ORM SQL ni o'zi yozadi.
Sequelize — Node.js uchun eng mashhur ORM lardan biri. PostgreSQL, MySQL, SQLite, MSSQL ni qo'llab-quvvatlaydi.
// SQL o'rniga — TypeScript ob'ekti
const user = await User.findOne({ where: { id: 1 } });
await User.create({ name: 'Ali', email: 'ali@example.com' });
await user.update({ name: 'Vali' });
await user.destroy();
O'rnatish
npm install @nestjs/sequelize sequelize sequelize-typescript pg pg-hstore
npm install --save-dev @types/sequelize
sequelize— asosiy kutubxonasequelize-typescript— TypeScript decorator qo'llab-quvvatlashpg— PostgreSQL driverpg-hstore— PostgreSQL hstore turi uchun
Ulanish
// app.module.ts
import { Module } from '@nestjs/common';
import { SequelizeModule } from '@nestjs/sequelize';
import { ConfigModule, ConfigService } from '@nestjs/config';
@Module({
imports: [
ConfigModule.forRoot({ isGlobal: true }),
SequelizeModule.forRootAsync({
useFactory: (config: ConfigService) => ({
dialect: 'postgres',
host: config.get('DB_HOST'),
port: config.get<number>('DB_PORT'),
username: config.get('DB_USERNAME'),
password: config.get('DB_PASSWORD'),
database: config.get('DB_NAME'),
autoSync: true, // modellar asosida jadvallarni avtomatik yaratadi
// ⚠️ autoSync: true — faqat development da! Production da migration ishlatiladi
}),
inject: [ConfigService],
}),
],
})
export class AppModule {}
.env:
DB_HOST=localhost
DB_PORT=5432
DB_USERNAME=postgres
DB_PASSWORD=secret
DB_NAME=myapp
Model yaratish
Model — ma'lumotlar bazasidagi jadvalning TypeScript ko'rinishi. Har bir property — jadval ustuni.
// users/user.model.ts
import {
Column,
DataType,
Model,
Table,
CreatedAt,
UpdatedAt,
} from 'sequelize-typescript';
@Table({ tableName: 'users' })
export class User extends Model {
@Column({ primaryKey: true, autoIncrement: true })
id: number;
@Column({ allowNull: false })
name: string;
@Column({ unique: true, allowNull: false })
email: string;
@Column({ defaultValue: 'user' })
role: string;
@Column({ type: DataType.BOOLEAN, defaultValue: true })
isActive: boolean;
@CreatedAt
createdAt: Date;
@UpdatedAt
updatedAt: Date;
}
@Table — bu class qaysi jadvalga mos kelishini bildiradi.
@Column — jadval ustuni. allowNull, unique, defaultValue kabi cheklovlar shu yerda.
@CreatedAt, @UpdatedAt — Sequelize avtomatik to'ldiradi.
Module va Service
// users/users.module.ts
import { Module } from '@nestjs/common';
import { SequelizeModule } from '@nestjs/sequelize';
import { User } from './user.model';
import { UsersService } from './users.service';
import { UsersController } from './users.controller';
@Module({
imports: [SequelizeModule.forFeature([User])], // bu modul User modelini ishlatadi
providers: [UsersService],
controllers: [UsersController],
})
export class UsersModule {}
SequelizeModule.forFeature([User]) — nima uchun kerak? Bu UsersService ga User modelini inject qilish imkonini beradi. Har bir modul faqat o'zi ishlatadigan modellarni ro'yxatga oladi.
// users/users.service.ts
import { Injectable, NotFoundException } from '@nestjs/common';
import { InjectModel } from '@nestjs/sequelize';
import { User } from './user.model';
@Injectable()
export class UsersService {
constructor(
@InjectModel(User) private readonly userModel: typeof User,
) {}
// CREATE
async create(data: { name: string; email: string }): Promise<User> {
return this.userModel.create(data);
}
// READ ALL
async findAll(): Promise<User[]> {
return this.userModel.findAll();
}
// READ ONE
async findOne(id: number): Promise<User> {
const user = await this.userModel.findByPk(id);
if (!user) throw new NotFoundException(`Foydalanuvchi #${id} topilmadi`);
return user;
}
// UPDATE
async update(id: number, data: Partial<{ name: string; role: string }>): Promise<User> {
const user = await this.findOne(id);
return user.update(data);
}
// DELETE
async remove(id: number): Promise<void> {
const user = await this.findOne(id);
await user.destroy();
}
}
@InjectModel(User) — User modelini inject qiladi. typeof User — model instance emas, model klassi (static metodlar uchun).
Controller
// users/users.controller.ts
import { Controller, Get, Post, Put, Delete, Param, Body, ParseIntPipe } from '@nestjs/common';
import { UsersService } from './users.service';
@Controller('users')
export class UsersController {
constructor(private readonly usersService: UsersService) {}
@Post()
create(@Body() body: { name: string; email: string }) {
return this.usersService.create(body);
}
@Get()
findAll() {
return this.usersService.findAll();
}
@Get(':id')
findOne(@Param('id', ParseIntPipe) id: number) {
return this.usersService.findOne(id);
}
@Put(':id')
update(
@Param('id', ParseIntPipe) id: number,
@Body() body: { name?: string; role?: string },
) {
return this.usersService.update(id, body);
}
@Delete(':id')
remove(@Param('id', ParseIntPipe) id: number) {
return this.usersService.remove(id);
}
}
Foydali so'rovlar
// Filtr bilan qidirish
const activeUsers = await this.userModel.findAll({
where: { isActive: true, role: 'admin' },
});
// Faqat kerakli ustunlar
const users = await this.userModel.findAll({
attributes: ['id', 'name', 'email'], // password, role kelmaydi
});
// Tartib va limit
const users = await this.userModel.findAll({
order: [['createdAt', 'DESC']],
limit: 10,
offset: 0, // pagination uchun
});
// Yoki topilmasa null
const user = await this.userModel.findOne({
where: { email: 'ali@example.com' },
});
// Mavjud bo'lsa qaytaradi, bo'lmasa yaratadi
const [user, created] = await this.userModel.findOrCreate({
where: { email: 'ali@example.com' },
defaults: { name: 'Ali' },
});
Tez-tez uchraydigan xatolar
1. SequelizeModule.forFeature unutilgan
Error: Nest can't resolve dependencies of the UsersService.
Please make sure that the argument InjectModel(User) is available.
Sabab: UsersModule da SequelizeModule.forFeature([User]) yo'q.
// ✅ To'g'ri
@Module({
imports: [SequelizeModule.forFeature([User])],
...
})
2. autoSync production da yoqilgan
autoSync: true — har ishga tushganda jadval tuzilmasini model bilan moslashtiradi. Agar model o'zgarsa — mavjud ma'lumotlar o'chib ketishi mumkin.
// ❌ Production da xavfli
autoSync: true
// ✅ Production da migration ishlatiladi (15-dars)
autoSync: process.env.NODE_ENV !== 'production'
3. findByPk null qaytaradi — tekshirilmagan
// ❌ user null bo'lsa — keyingi qatorda crash
const user = await this.userModel.findByPk(id);
return user.name; // TypeError: Cannot read properties of null
// ✅ Har doim tekshiring
const user = await this.userModel.findByPk(id);
if (!user) throw new NotFoundException(`Foydalanuvchi #${id} topilmadi`);
return user.name;
Xulosa
Sequelize nima beradi:
- SQL yozmasdan TypeScript ob'ektlari bilan ishlash
- SQL injection dan himoya (parametrlar avtomatik escaped)
- PostgreSQL, MySQL, SQLite — bir xil kod
Asosiy metodlar:
| Metod | Nima qiladi |
|---|---|
Model.create(data) |
Yangi yozuv yaratadi |
Model.findAll({ where }) |
Barcha mos yozuvlarni qaytaradi |
Model.findByPk(id) |
ID bo'yicha topadi |
Model.findOne({ where }) |
Birinchi mos yozuvni topadi |
instance.update(data) |
Yozuvni yangilaydi |
instance.destroy() |
Yozuvni o'chiradi |
Keyingi dars
14-dars: Database Relations — One-to-Many, Many-to-Many (Sequelize)