首页 > 解决方案 > 是否可以在 TypeORM 的 leftJoinAndSelect 中使用子查询

问题描述

所以我有一个关于nestjs 并使用TypeORM 的项目。我的情况是我有一个与 UserSubscrtion 有一对一关系的用户。默认查找查询将所有订阅添加到用户,因为它应该是。所以现在我想找到一个特定的订阅,例如最后添加的。所以我建立了这个查询:

    const query = this.createQueryBuilder("user")
    .leftJoinAndSelect("user.settings", "settings")
    .leftJoinAndSelect( 
      subQuery => {
          return subQuery
              .select()
              .from(UserSubscription, "subscription")
              .where("subscription.userId = :id AND subscription.isConfirmed = :isConfirmed", { id, isConfirmed: true })
              .orderBy('"createdDate"', 'DESC')
              .limit(1);
      }, 'subscription', '"subscription"."userId" = "user"."id"')
    .where('user.id = :id', { id });
    const result = await query.getOne(); // await query.execute()

首先,我尝试只执行查询,它工作正常,但所有数据都不是结构化的

[
  {
    user_id: 1,
    user_username: 'name',
    ...
    settings_id: 1,
    settings_ifOnline: true,
    ...
    subscriptions_id: 1,
    subscriptions_subscriptionId: 1,
    ...
  }
]

所以不好。

然后我尝试 query.getOne() 但它无法按我的意愿工作,它丢失了所有订阅数据

User {
  id: 1,
  username: 'name',
  ...
  settings: UserNotificationSettings {
    id: 1,
    ifOnline: true,
    ...
  }
}

另外,我尝试将虚拟字段订阅添加到用户实体并尝试使用 leftJoinAndMapOne:

    ...
    .leftJoinAndSelect("user.settings", "settings")
    .leftJoinAndMapOne("user.subscription", 
      subQuery => {
          return subQuery
              .select()
              .from(UserSubscription, "subscription")
              .where("subscription.userId = :id AND subscription.isConfirmed = :isConfirmed", { id, isConfirmed: true })
              .orderBy('"createdDate"', 'DESC')
              .limit(1);
      }, 'subscription', '"subscription"."userId" = "user"."id"')
    ...

但没有运气。在文档中,据说“FROM、WHERE 和 JOIN 表达式支持子查询”。但没有提供示例。所以,我不知道如何处理这个我相信使用 TypeORM 的查询非常简单。有什么建议么?我有点坚持这个。可能有比 buildibg 查询更好的方法吗?谢谢。

用户实体

 export class User extends BaseEntity {
  @PrimaryGeneratedColumn()
  id: number;
  ...

  // subscription: UserSubscription;

  @OneToMany(type => UserSubscription, subscriptions => subscriptions.user, { cascade:true })
  subscriptions: UserSubscription[];

  @OneToOne(type => UserNotificationSettings, settings => settings.user, { cascade:true })
  settings: UserNotificationSettings;
}

用户订阅实体

export class UserSubscription extends BaseEntity {
  @PrimaryGeneratedColumn()
  id: number;

  @OneToOne(type => Subscription)
  @JoinColumn()
  subscription: Subscription

  @Column()
  subscriptionId: number

  @ManyToOne(type => User, user => user.subscriptions)
  user: User

  @Column({type: 'integer'})
  userId: number

  @Column({ type: 'boolean', default: false })
  isConfirmed: boolean

  ...
}

标签: nestjstypeorm

解决方案


使用该SubQueryFactory选项不会自动将on子句创建为条件,因为它无法知道您尝试加入的基础查询的别名是什么。.leftJoinAndSelect('user.photos', 'photos')由于它的编写方式,它没有元数据提供的上下文。

相反,您必须明确定义条件。在你的情况下:

const result = await userRepo
                     .createQueryBuilder('user')
                     .leftJoinAndSelect(
                         qb => qb
                            .select()
                            .from(UserPhotos, 'p')
                            .orderBy({ 'p.updatedAt': 'ASC' })
                            .limit(5),
                         'photos',
                         'photos.userId = user.id' // the answer
                     )
                     .getRawMany() // .getMany() seems not working

这是实际答案: https ://github.com/typeorm/typeorm/issues/6767

更新

我看到.getMany()使用SubQueryFactory. 您可以使用.getRawMany().


推荐阅读