TypeORM中如何不加载完整子实体获取子实体ID?
不用QueryBuilder实现获取用户的courseIds数组
有两种无需QueryBuilder的方案可以满足你的需求,具体如下:
方案一:使用@Formula定义数据库计算列(推荐)
利用TypeORM的@Formula装饰器,直接在数据库层面聚合用户关联的课程ID,无需加载任何CourseModel实体,性能最优。
PostgreSQL 版本
@Entity('user') class UserModel { @PrimaryColumn({ name: 'id', type: 'varchar', }) id: Ulid = generate() // 新增courseIds字段,通过数据库聚合查询获取 @Formula((alias) => `(SELECT ARRAY_AGG(c.id) FROM course c WHERE c.user_id = ${alias}.id)`) courseIds: string[]; @OneToMany(() => CourseModel, (course) => course.user) courses?: CourseModel[] }
MySQL 版本
MySQL不支持原生数组类型,可通过GROUP_CONCAT拼接ID,再用getter转为数组:
@Entity('user') class UserModel { @PrimaryColumn({ name: 'id', type: 'varchar', }) id: Ulid = generate() @Formula((alias) => `(SELECT GROUP_CONCAT(c.id SEPARATOR ',') FROM course c WHERE c.user_id = ${alias}.id)`) private _courseIds: string; @OneToMany(() => CourseModel, (course) => course.user) courses?: CourseModel[] // 自定义getter转为数组 get courseIds(): string[] { return this._courseIds ? this._courseIds.split(',') : []; } }
使用时直接查询用户即可自动获取courseIds:
const users = await userRepository.find({ select: ['id', 'courseIds'] // 按需指定字段,默认会包含所有实体字段 });
方案二:关联字段仅加载ID+getter提取
通过配置@OneToMany的select选项,只加载课程的ID字段,再用getter提取ID数组,这种方式跨数据库兼容,无需依赖特定数据库语法。
@Entity('user') class UserModel { @PrimaryColumn({ name: 'id', type: 'varchar', }) id: Ulid = generate() @OneToMany(() => CourseModel, (course) => course.user, { select: ['id'], // 仅加载CourseModel的id字段 eager: false // 按需加载,若需自动关联可设为true }) courses?: Pick<CourseModel, 'id'>[] // 自定义getter提取课程ID数组 get courseIds(): string[] { return this.courses?.map(course => course.id) || []; } }
使用时需要确保courses被加载(懒加载需手动调用loadRelation,或设为eager: true自动加载):
// 方式1:手动加载关联 const user = await userRepository.findOne({ where: { id: 'xxx' } }); await userRepository.loadRelation(user, 'courses'); console.log(user.courseIds); // 方式2:eager自动加载 const user = await userRepository.findOne({ where: { id: 'xxx' } }); console.log(user.courseIds);
两种方案对比
- @Formula方案:性能最好,无需加载任何关联实体,但依赖数据库语法,不同数据库需要调整SQL。
- 关联select+getter方案:跨数据库兼容,实现简单,但会加载课程的ID字段,性能略逊于前者。
内容的提问来源于stack exchange,提问作者Sannnekk
相关产品推荐
相关产品推荐

