Database Operations
We've connected to the database and defined our Entity. Now we can perform CRUD operations using TypeORM's Repository API.
The Repository
In TypeORM, a Repository is the interface between your application and a specific database table. You get a repository for an entity like this:
const personRepository = AppDataSource.getRepository(Person);
The repository gives you methods to save, find, update, and delete rows — without writing SQL.
Record, Row, and Document all mean the same thing in different contexts. In PostgreSQL, we call it a row or record. In MongoDB, it's a document. TypeORM works with instances of your Entity class.
Create (Insert)
save()
save() is the most flexible method. It creates a new row if the entity has no id, or updates an existing row if it does.
const person = personRepository.create({
name: "Rizwan Ashiq",
age: 25,
email: "rizwan@example.com",
gender: "male",
});
const saved = await personRepository.save(person);
console.log(saved);
// { id: 1, name: 'Rizwan Ashiq', age: 25, email: 'rizwan@example.com', ... }
Note: create() builds the entity object in memory. save() actually writes it to the database.
You can also use save() directly with a plain object:
const saved = await personRepository.save({
name: "Ashiq Ashiq",
age: 30,
email: "ashiq@example.com",
gender: "female",
});
insert()
insert() is a low-level bulk insert. It does not go through entity lifecycle hooks and is faster for large inserts.
await personRepository.insert([
{ name: "Person 1", age: 20, email: "p1@example.com", gender: "male" },
{ name: "Person 2", age: 22, email: "p2@example.com", gender: "female" },
]);
Read (Select)
find()
Returns all rows that match the given conditions. Returns an empty array if none match.
All Rows
const persons = await personRepository.find();
console.log(persons); // [{ id: 1, name: 'Rizwan', ... }, ...]
Filtered Rows
Pass a where condition to filter:
const persons = await personRepository.find({
where: { gender: "male" },
});
You can use multiple conditions (acts as AND):
const persons = await personRepository.find({
where: { gender: "male", isAlive: true },
});
Sorting
const persons = await personRepository.find({
order: { age: "ASC" },
});
Limiting Results
const persons = await personRepository.find({
take: 10, // LIMIT 10
skip: 0, // OFFSET 0
});
Loading Relations
To load related entities (like populating in Mongoose), use relations:
const posts = await postRepository.find({
relations: { author: true },
});
// post.author will be the full User object
findOne()
Returns the first row that matches, or null if none found.
const person = await personRepository.findOne({
where: { email: "rizwan@example.com" },
});
if (!person) {
// handle not found
}
findOneBy()
A shorthand for findOne({ where: ... }):
const person = await personRepository.findOneBy({ id: 1 });
Advanced Queries with FindOperators
TypeORM provides operators for more complex where conditions, imported from typeorm:
import { Like, MoreThan, LessThan, In, Not, IsNull } from "typeorm";
| Operator | Description | Example |
|---|---|---|
Like | SQL LIKE pattern match | where: { name: Like("%rizwan%") } |
ILike | Case-insensitive LIKE | where: { name: ILike("%rizwan%") } |
MoreThan | Greater than | where: { age: MoreThan(18) } |
LessThan | Less than | where: { age: LessThan(60) } |
Between | Between two values | where: { age: Between(18, 30) } |
In | Value in an array | where: { gender: In(["male", "female"]) } |
Not | Negate a condition | where: { gender: Not("other") } |
IsNull | Column is NULL | where: { phone: IsNull() } |
Example:
import { MoreThan, ILike } from "typeorm";
const persons = await personRepository.find({
where: {
age: MoreThan(18),
name: ILike("%rizwan%"),
},
});
count()
Returns the number of rows matching the condition:
const totalAdults = await personRepository.count({
where: { age: MoreThan(18) },
});
Update
save() — Update an Existing Row
The easiest way to update is to fetch the row, modify it, and call save(). TypeORM detects the id and issues an UPDATE instead of INSERT.
const person = await personRepository.findOneBy({ id: 1 });
if (person) {
person.age = 26;
await personRepository.save(person);
}
update()
update() lets you update rows by criteria without fetching them first. It is faster but does not trigger TypeORM lifecycle hooks.
await personRepository.update({ id: 1 }, { age: 27 });
// Or shorthand with just the id:
await personRepository.update(1, { age: 27 });
It does not return the updated entity. If you need the updated row, fetch it separately:
await personRepository.update(1, { age: 27 });
const updated = await personRepository.findOneBy({ id: 1 });
Partial Update vs Full Replace
save() only updates the fields you set on the object. update() only updates the fields you pass in the second argument. Neither of these replaces the whole row (unlike replaceOne in Mongoose). To replace all columns, fetch the entity and reassign all fields before saving.
Delete
delete()
Deletes rows by condition or by ID.
await personRepository.delete(1);
// Or by criteria:
await personRepository.delete({ gender: "other" });
delete() returns a result object with affected — the number of rows deleted.
const result = await personRepository.delete(1);
console.log(result.affected); // 1
Calling delete({}) with an empty object will throw an error in TypeORM (to prevent accidental deletion of all rows). To delete all rows, use personRepository.clear().
remove()
remove() takes an entity instance (or array of instances) and deletes them. It goes through lifecycle hooks.
const person = await personRepository.findOneBy({ id: 1 });
if (person) {
await personRepository.remove(person);
}
Soft Delete
If your entity has a @DeleteDateColumn(), you can use soft deletes instead of permanently removing rows:
await personRepository.softDelete(1);
The row remains in the database but has a deletedAt timestamp. Regular find() calls automatically exclude soft-deleted rows. To include them:
const allIncludeDeleted = await personRepository.find({
withDeleted: true,
});
To restore a soft-deleted row:
await personRepository.restore(1);
Conclusion
In this doc, we learned how to perform CRUD operations in TypeORM using the Repository API. We covered:
save()andinsert()for creating rowsfind(),findOne(),findOneBy()and operators for reading rowssave()andupdate()for modifying rowsdelete(),remove(), and soft deletes for removing rows
In the next doc, we'll put it all together in a full Express + TypeORM example.