如何在TypeORM QueryBuilder中用getOne()获取JSONB列指定键值?
解决TypeORM QueryBuilder中getOne()获取JSONB指定键值的问题
要让getOne()正确映射JSONB字段的指定键值,核心是让查询结果的别名与实体中的属性一一对应——因为getOne()会自动将查询结果映射到实体类的属性上。以下是两种可行方案:
方案一:新增实体属性并指定查询别名
- 修改Workout实体:添加一个用于接收目标键值的属性,设置
select: false避免默认查询该字段:
import { Entity, Column, PrimaryGeneratedColumn } from 'typeorm'; @Entity('workouts') export class Workout { @PrimaryGeneratedColumn('uuid') uuid: string; @Column('jsonb') name: Record<string, string>; // 原JSONB类型字段 // 新增属性,用于存储name中'it'键对应的值 @Column({ type: 'text', nullable: true, select: false }) nameIt: string; }
- 调整QueryBuilder代码:将JSONB提取的结果别名设为新增的实体属性名:
const workout = await this.workouts .createQueryBuilder('workout') .select(['workout.uuid', `workout.name ->> 'it'` as 'nameIt']) .where('workout.uuid = :workoutUuid', { workoutUuid }) .getOne(); return workout; // 此时workout.nameIt会包含JSONB中'it'键的值
方案二:使用@AfterLoad钩子(加载后提取)
如果不想新增数据库映射属性,可以用实体的加载钩子在查询完成后从JSONB字段中提取值:
- 修改Workout实体:添加临时属性和加载钩子:
import { Entity, Column, PrimaryGeneratedColumn, AfterLoad } from 'typeorm'; @Entity('workouts') export class Workout { @PrimaryGeneratedColumn('uuid') uuid: string; @Column('jsonb') name: Record<string, string>; // 临时属性,无需@Column注解 nameIt?: string; @AfterLoad() loadItalianName() { // 从JSONB字段中提取'it'键的值 this.nameIt = this.name?.['it']; } }
- 调整QueryBuilder代码:只需查询原有的JSONB字段即可,钩子会自动处理:
const workout = await this.workouts .createQueryBuilder('workout') .select(['workout.uuid', 'workout.name']) .where('workout.uuid = :workoutUuid', { workoutUuid }) .getOne(); return workout; // workout.nameIt会自动加载'it'键的值
注意:方案一直接在数据库查询时提取值,性能更优;方案二更适合需要从JSONB中提取多个键值的场景,但会先加载整个JSONB字段。
内容的提问来源于stack exchange,提问作者Bigbool98
相关产品推荐
相关产品推荐

