Crud_operations
Chapter 12: CRUD Operations
Section titled “Chapter 12: CRUD Operations”Complete Guide to Create, Read, Update, and Delete Operations
Section titled “Complete Guide to Create, Read, Update, and Delete Operations”12.1 CRUD Overview
Section titled “12.1 CRUD Overview”CRUD operations are the fundamental operations for any database application.
CRUD Operations Flow ================================================================================
CRUD Operations | +-----------+-----------+-----------+-----------+ | | | | | v v v v v +-------+ +-------+ +-------+ +-------+ +-------+ | CREATE| | READ | | UPDATE| | DELETE| | COUNT | +-------+ +-------+ +-------+ +-------+ +-------+ | | | | | v v v v v INSERT SELECT UPDATE DELETE COUNT save() find() save() remove() count() insert() findOne() update() delete() create() findBy()
================================================================================12.2 Create Operations
Section titled “12.2 Create Operations”Using create() + save()
Section titled “Using create() + save()”import { AppDataSource } from './data-source';import { User } from './entities/user.entity';
const userRepository = AppDataSource.getRepository(User);
// Step 1: Create entity instance (not saved)const user = userRepository.create({ name: 'John Doe', email: 'john@example.com', isActive: true,});
// Step 2: Save to databaseawait userRepository.save(user);
console.log(user.id); // Auto-generated IDUsing save() directly
Section titled “Using save() directly”// Create and save in one stepconst user = new User();user.name = 'John Doe';user.email = 'john@example.com';
await userRepository.save(user);Using insert()
Section titled “Using insert()”// Insert is faster for new entities// Returns insert result, not entityconst result = await userRepository.insert({ name: 'John Doe', email: 'john@example.com',});
console.log(result.identifiers); // [{ id: 1 }]Bulk Create
Section titled “Bulk Create”// Method 1: Using save() with arrayconst users = userRepository.create([ { name: 'User 1', email: 'user1@example.com' }, { name: 'User 2', email: 'user2@example.com' }, { name: 'User 3', email: 'user3@example.com' },]);await userRepository.save(users);
// Method 2: Using insert() with arrayawait userRepository.insert([ { name: 'User 1', email: 'user1@example.com' }, { name: 'User 2', email: 'user2@example.com' }, { name: 'User 3', email: 'user3@example.com' },]);Create with Relations
Section titled “Create with Relations”// Create user with postsconst user = userRepository.create({ name: 'John Doe', email: 'john@example.com', posts: [ { title: 'First Post', content: 'Content 1' }, { title: 'Second Post', content: 'Content 2' }, ],});
await userRepository.save(user);// Inserts user AND posts (if cascade is enabled)12.3 Read Operations
Section titled “12.3 Read Operations”Find All
Section titled “Find All”// Get all usersconst users = await userRepository.find();
// With conditionsconst activeUsers = await userRepository.find({ where: { isActive: true },});Find One
Section titled “Find One”// Find by IDconst user = await userRepository.findOne({ where: { id: 1 },});
// Find by conditionconst user = await userRepository.findOne({ where: { email: 'john@example.com' },});
// Find or throwconst user = await userRepository.findOneOrFail({ where: { id: 1 },});// Throws EntityNotFoundError if not foundFind By
Section titled “Find By”// Simple find by conditionsconst users = await userRepository.findBy({ isActive: true, role: 'admin',});Find with Relations
Section titled “Find with Relations”// Load related entitiesconst user = await userRepository.findOne({ where: { id: 1 }, relations: ['posts', 'posts.comments', 'profile'],});
console.log(user.posts[0].comments);Find with Select
Section titled “Find with Select”// Select specific columnsconst users = await userRepository.find({ select: ['id', 'name', 'email'],});
// Select with relationsconst user = await userRepository.findOne({ where: { id: 1 }, select: { id: true, name: true, posts: { id: true, title: true, }, }, relations: ['posts'],});Find with Order
Section titled “Find with Order”// Order by single columnconst users = await userRepository.find({ order: { createdAt: 'DESC' },});
// Order by multiple columnsconst users = await userRepository.find({ order: { role: 'ASC', createdAt: 'DESC', },});Pagination
Section titled “Pagination”// Skip and takeconst users = await userRepository.find({ skip: 0, // Offset take: 10, // Limit});
// With page numberconst page = 2;const limit = 10;const users = await userRepository.find({ skip: (page - 1) * limit, take: limit,});
// Find and count (for pagination info)const [users, total] = await userRepository.findAndCount({ skip: 0, take: 10,});
console.log(`Page 1 of ${Math.ceil(total / 10)}`);12.4 Update Operations
Section titled “12.4 Update Operations”Using save()
Section titled “Using save()”// Find, modify, saveconst user = await userRepository.findOne({ where: { id: 1 } });user.name = 'Updated Name';user.email = 'updated@example.com';await userRepository.save(user);Using update()
Section titled “Using update()”// Update by conditionawait userRepository.update( { id: 1 }, { name: 'Updated Name' });
// Update multipleawait userRepository.update( { isActive: false }, { isActive: true });
// Update by IDawait userRepository.update(1, { name: 'Updated Name' });Using preload()
Section titled “Using preload()”// Preload creates entity from existing dataconst user = await userRepository.preload({ id: 1, name: 'Updated Name', email: 'updated@example.com',});
if (user) { await userRepository.save(user);}Partial Update
Section titled “Partial Update”// Update only provided fieldsconst updateData: Partial<User> = { name: 'New Name',};
await userRepository.update({ id: 1 }, updateData);// Only 'name' is updated, other fields remain unchangedUpdate with Relations
Section titled “Update with Relations”// Update user and add new postconst user = await userRepository.findOne({ where: { id: 1 }, relations: ['posts'],});
user.posts.push({ title: 'New Post', content: 'Content' });await userRepository.save(user);12.5 Delete Operations
Section titled “12.5 Delete Operations”Using remove()
Section titled “Using remove()”// Remove entity instanceconst user = await userRepository.findOne({ where: { id: 1 } });await userRepository.remove(user);
// Remove multipleconst users = await userRepository.find({ where: { isActive: false } });await userRepository.remove(users);Using delete()
Section titled “Using delete()”// Delete by IDawait userRepository.delete(1);
// Delete by conditionawait userRepository.delete({ isActive: false });
// Delete multiple IDsawait userRepository.delete([1, 2, 3]);Soft Delete
Section titled “Soft Delete”// Soft delete (sets deletedAt)await userRepository.softDelete(1);
// Soft remove entity instanceconst user = await userRepository.findOne({ where: { id: 1 } });await userRepository.softRemove(user);
// Find including soft deletedconst allUsers = await userRepository.find({ withDeleted: true,});
// Restore soft deletedawait userRepository.restore(1);12.6 Complete CRUD Service Example
Section titled “12.6 Complete CRUD Service Example”import { Injectable, NotFoundException } from '@nestjs/common';import { InjectRepository } from '@nestjs/typeorm';import { Repository } from 'typeorm';import { User } from './user.entity';import { CreateUserDto } from './dto/create-user.dto';import { UpdateUserDto } from './dto/update-user.dto';
@Injectable()export class UsersService { constructor( @InjectRepository(User) private userRepository: Repository<User>, ) {}
// CREATE async create(createUserDto: CreateUserDto): Promise<User> { const user = this.userRepository.create(createUserDto); return this.userRepository.save(user); }
// READ - All async findAll(page = 1, limit = 10): Promise<{ data: User[]; total: number }> { const [data, total] = await this.userRepository.findAndCount({ skip: (page - 1) * limit, take: limit, order: { createdAt: 'DESC' }, });
return { data, total }; }
// READ - One async findOne(id: number): Promise<User> { const user = await this.userRepository.findOne({ where: { id }, relations: ['posts'], });
if (!user) { throw new NotFoundException(`User with ID ${id} not found`); }
return user; }
// UPDATE async update(id: number, updateUserDto: UpdateUserDto): Promise<User> { const user = await this.userRepository.preload({ id, ...updateUserDto, });
if (!user) { throw new NotFoundException(`User with ID ${id} not found`); }
return this.userRepository.save(user); }
// DELETE async remove(id: number): Promise<void> { const user = await this.findOne(id); await this.userRepository.remove(user); }
// SOFT DELETE async softDelete(id: number): Promise<void> { const user = await this.findOne(id); await this.userRepository.softRemove(user); }
// RESTORE async restore(id: number): Promise<User> { await this.userRepository.restore(id); return this.findOne(id); }}12.7 CRUD with QueryBuilder
Section titled “12.7 CRUD with QueryBuilder”For more complex operations, use QueryBuilder.
// Create with QueryBuilderawait userRepository .createQueryBuilder() .insert() .into(User) .values([ { name: 'User 1', email: 'user1@example.com' }, { name: 'User 2', email: 'user2@example.com' }, ]) .execute();
// Read with QueryBuilderconst users = await userRepository .createQueryBuilder('user') .leftJoinAndSelect('user.posts', 'post') .where('user.isActive = :active', { active: true }) .orderBy('user.createdAt', 'DESC') .getMany();
// Update with QueryBuilderawait userRepository .createQueryBuilder() .update(User) .set({ isActive: false }) .where('lastLoginAt < :date', { date: new Date('2023-01-01') }) .execute();
// Delete with QueryBuilderawait userRepository .createQueryBuilder() .delete() .from(User) .where('isActive = :active', { active: false }) .execute();12.8 CRUD Best Practices
Section titled “12.8 CRUD Best Practices” CRUD Best Practices +------------------------------------------------------------------+ | | | 1. Use save() for most operations | | - Handles both insert and update | | - Works with relations | | | | 2. Use insert() for bulk inserts | | - More efficient for large datasets | | - No entity overhead | | | | 3. Use update() for simple updates | | - No need to fetch entity first | | - More efficient | | | | 4. Always check if entity exists | | - Use findOneOrFail() or check null | | - Throw appropriate exceptions | | | | 5. Use transactions for related operations | | - Ensure data consistency | | - Rollback on failure | | | | 6. Use soft delete for important data | | - Preserve data for recovery | | - Maintain audit trail | | | +------------------------------------------------------------------+12.9 Error Handling in CRUD
Section titled “12.9 Error Handling in CRUD”import { EntityNotFoundError, QueryFailedError } from 'typeorm';
async function safeUpdate(id: number, data: UpdateUserDto) { try { const user = await userRepository.preload({ id, ...data });
if (!user) { throw new NotFoundException('User not found'); }
return await userRepository.save(user);
} catch (error) { if (error instanceof QueryFailedError) { // Handle database errors const driverError = error.driverError;
if (driverError.code === '23505') { throw new ConflictException('Email already exists'); }
throw new InternalServerErrorException('Database error'); }
throw error; }}12.10 Summary
Section titled “12.10 Summary” CRUD Operations Quick Reference +------------------------------------------------------------------+ | | | Operation | Method | Returns | | -------------------|--------------------|-------------------- | | Create | save(entity) | Entity | | Create | insert(data) | InsertResult | | Read All | find(options) | Entity[] | | Read One | findOne(options) | Entity | null | | Read One | findOneOrFail() | Entity | | Read Count | count(options) | number | | Update | save(entity) | Entity | | Update | update(cond, data) | UpdateResult | | Delete | remove(entity) | Entity | | Delete | delete(condition) | DeleteResult | | Soft Delete | softRemove(entity) | Entity | | Soft Delete | softDelete(cond) | UpdateResult | | Restore | restore(condition) | UpdateResult | | | +------------------------------------------------------------------+Next Chapter
Section titled “Next Chapter”Chapter 13: Find Options & Querying
Last Updated: February 2026