Nest 与数据库无关,允许您轻松地与任何 SQL 或 NoSQL 数据库集成。根据您的偏好,您有许多可用的选项。一般来说,将 Nest 连接到数据库只需为数据库加载一个适当的 Node.js 驱动程序,就像使用 Express 或 Fastify 一样。
官方文档:www.typeorm.org/
TypeORM 集成
$ npm install --save @nestjs/typeorm typeorm mysql2
将 TypeOrmModule 导入AppModule。app.module.ts
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
@Module({
imports: [
TypeOrmModule.forRoot({
type: 'mysql',// 数据库类型名称
host: 'localhost',// 地址,这里是本机回环地址
port: 3306,// 端口号
username: 'root',// 用户名
password: 'root',// 用户密码
database: 'test',//数据库名称,需要已经建立的数据库
// 从当前目录及其子目录中的所有 .entity 文件加载实体。
// entities: [__dirname + '/**/*.entity{.ts,.js}'],
entities: [],
synchronize: true,// 自动同步数据库
}),
],
})
export class AppModule {}
我们可以创建 ormconfig.json ,而不是将配置对象传递给 forRoot()。
{
"type": "mysql",
"host": "localhost",
"port": 3306,
"username": "root",
"password": "root",
"database": "test",
"entities": ["dist/**/*.entity{.ts,.js}"],
"synchronize": true
}
app.module.ts
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
@Module({
imports: [TypeOrmModule.forRoot()],
})
export class AppModule {}
存储库模式
TypeORM 支持存储库设计模式,因此每个实体都有自己的存储库。可以从数据库连接获得这些存储库。为了继续这个示例,我们需要至少一个实体。我们来定义User 实体。 user.entity.ts
import { Entity, Column, PrimaryGeneratedColumn } from 'typeorm';
@Entity()
export class User {
@PrimaryGeneratedColumn()
id: number;
@Column()
firstName: string;
@Column()
lastName: string;
@Column({ default: true })
isActive: boolean;
}
app.module.ts
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { User } from './users/user.entity';
@Module({
imports: [
TypeOrmModule.forRoot({
type: 'mysql',
host: 'localhost',
port: 3306,
username: 'root',
password: 'root',
database: 'test',
entities: [User],
synchronize: true,
}),
],
})
export class AppModule {}
user.module.ts
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { UsersService } from './users.service';
import { UsersController } from './users.controller';
import { User } from './user.entity';
@Module({
imports: [TypeOrmModule.forFeature([User])],
providers: [UsersService],
controllers: [UsersController],
})
export class UsersModule {}
users.service.ts
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { User } from './user.entity';
@Injectable()
export class UsersService {
constructor(
@InjectRepository(User)
private usersRepository: Repository<User>
) {}
findAll(): Promise<User[]> {
return this.usersRepository.find();
}
findOne(id: string): Promise<User> {
return this.usersRepository.findOne(id);
}
async remove(id: string): Promise<void> {
await this.usersRepository.delete(id);
}
}
事务
数据库事务代表在数据库管理系统(DBMS)中针对数据库的一组操作,这组操作是有关的、可靠的并且和其他事务相互独立的。
@Injectable()
export class UsersService {
constructor(private connection: Connection) {}
}
......
async createMany(users: User[]) {
const queryRunner = this.connection.createQueryRunner();
await queryRunner.connect();
await queryRunner.startTransaction();
try {
await queryRunner.manager.save(users[0]);
await queryRunner.manager.save(users[1]);
await queryRunner.commitTransaction();
} catch (err) {
//如果遇到错误,可以回滚事务
await queryRunner.rollbackTransaction();
} finally {
//你需要手动实例化并部署一个queryRunner
await queryRunner.release();
}
}
async createMany(users: User[]) {
await this.connection.transaction(async manager => {
await manager.save(users[0]);
await manager.save(users[1]);
});
}
多个数据库
某些项目可能需要多个数据库连接。这也可以通过本模块实现。要使用多个连接,首先要做的是创建这些连接。在这种情况下,连接命名成为必填项。
const defaultOptions = {
type: 'postgres',
port: 5432,
username: 'user',
password: 'password',
database: 'db',
synchronize: true,
};
@Module({
imports: [
TypeOrmModule.forRoot({
...defaultOptions,
host: 'user_db_host',
entities: [User],
}),
TypeOrmModule.forRoot({
...defaultOptions,
name: 'albumsConnection',
host: 'album_db_host',
entities: [Album],
}),
],
})
export class AppModule {}
分页、排序、条件查询
分页
async findAll(page: number, limit: number): Promise<Post[]> {
const posts = await this.postsRepository.find({
skip: (page - 1) * limit,
take: limit,
});
return posts;
}
async count(): Promise<number> {
return this.postsRepository.count();
}
// qb = qb.skip(pageParam.pageSize * (pageParam.current - 1)).take(pageParam.pageSize)
排序
async findAllSorted(sortBy: string, order: 'ASC' | 'DESC'): Promise<User[]> {
return this.usersRepository
.createQueryBuilder('user')
.orderBy(`user.${sortBy}`, order)
.getMany();
}
// 普通排序
qb = qb.orderBy('update_time', 'DESC')
// 自定义条件,且多重排序
// 例如:assignee字段为 ${userName} 的优先显示,然后再在此基础上再进行时间和状态的排序
qb = qb
.orderBy(`case assignee when assignee="${userName}" then 1 else 0 end`)
.addOrderBy('status', 'ASC')
.addOrderBy('update_time', 'DESC')
条件查询
async findUsersByCondition(name: string, age: number): Promise<User[]> {
const query = this.usersRepository.createQueryBuilder('user');
if (name) {
query.where('user.name = :name', { name });
}
if (age) {
query.andWhere('user.age = :age', { age });
}
return query.getMany();
}
保存
async createUser(userData: User): Promise<User> {
const newUser = this.usersRepository.create(userData);
return this.usersRepository.save(newUser);
}
关联多表查询
// user.entity.ts
import { Entity, PrimaryGeneratedColumn, Column, OneToMany } from 'typeorm';
import { PhotoEntity } from './photo.entity';
@Entity('users')
export class UserEntity {
@PrimaryGeneratedColumn()
id: number;
@Column()
name: string;
@OneToMany(() => PhotoEntity, (photo) => photo.user)
photos: PhotoEntity[];
}
// photo.entity.ts
import { Entity, PrimaryGeneratedColumn, Column, ManyToOne } from 'typeorm';
import { UserEntity } from './user.entity';
@Entity('photos')
export class PhotoEntity {
@PrimaryGeneratedColumn()
id: number;
@Column()
title: string;
@Column()
url: string;
@ManyToOne(() => UserEntity, (user) => user.photos)
user: UserEntity;
}
// users.service.ts
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { UserEntity } from './user.entity';
@Injectable()
export class UsersService {
constructor(
@InjectRepository(UserEntity)
private usersRepository: Repository<UserEntity>,
) {}
async findUserWithPhotos(userId: number): Promise<UserEntity> {
return this.usersRepository.findOne(userId, { relations: ['photos'] });
}
}