TypeORM:如何使用字符串数组输入查询多对多关系以查找所有字符串都应存在于相关实体的列中的实体?

ron*_*ory 6 javascript many-to-many typescript typeorm nestjs

我有一个与User实体具有 OneToOne 关系的实体Profile,并且该Profile实体与实体具有 ManyToMany 关系Category

// user.entity.ts

@Entity()
export class User {
  @PrimaryGeneratedColumn('uuid')
  id: string;

  @OneToOne(() => Profile, {
    cascade: true,
    nullable: true,
  })
  @JoinColumn() // user owns the relationship (User table contains profileId). Use it only on one side of the relationship
  profile: Profile;
}
Run Code Online (Sandbox Code Playgroud)
// profile.entity.ts

@Entity()
export class Profile {
  @PrimaryGeneratedColumn('uuid')
  id: number;

  @OneToOne(() => User, (user: User) => user.profile)
  user: User;

  @ManyToMany(() => Category, (category: Category) => category, {
    cascade: true,
    nullable: true,
  })
  @JoinTable()
  categories: Category[];
}
Run Code Online (Sandbox Code Playgroud)
// category.entity.ts

@Entity()
export class Category {
  @PrimaryGeneratedColumn('uuid')
  id: number;

  @Column()
  name: string;

  @ManyToMany(() => Profile, (profile: Profile) => profile.categories, {
    nullable: true,
  })
  profiles: Profile[];
}
Run Code Online (Sandbox Code Playgroud)

我的目标是获取所有用户实体,其中配置文件的类别名称全部存在于字符串数组中作为输入,例如const categories = ['category1', 'category2']。到目前为止,将IN与查询生成器一起使用使我接近我的目标。

这是使用 IN 的查询:

const categories = ['category1', 'category2']

const users = await this.usersRepository
  .createQueryBuilder('user')
  .innerJoinAndSelect('user.profile', 'profile')
  .innerJoinAndSelect('profile.categories', 'categories')
  .where('categories.name IN (:...categories)', {
    categories,
  })
  .getMany();
Run Code Online (Sandbox Code Playgroud)

我只想要category1ANDcategory2作为配置文件的多对多关系的名称出现的用户。通过上面的查询,我还收到仅其中一个值作为名称出现的用户。以我目前的结构来说这可能吗?

与我的接近,但 OP 有不相关的实体。

也很接近,但它只是一个用于过滤的字符串数组列。

另外,我想保留当前的结构,因为可能想向类别实体添加一些其他列,例如订单。

更新:

我决定使用字符串数组而不是多对多关系,因为它满足我自己的要求。

// profile.entity.ts

@Column('text', {
  nullable: true,
  array: true,
})
categories?: string[];
Run Code Online (Sandbox Code Playgroud)

更新后的查询:

const categories = ['category1', 'category2']

const users = await this.usersRepository
  .createQueryBuilder('user')
  .innerJoinAndSelect('user.profile', 'profile')
  .where('profile.categories::text[] @> (:categories)::text[]', {
    categories,
  })
  .getMany();
Run Code Online (Sandbox Code Playgroud)

jbo*_*oot 4

如果您使用 PostgreSQL,则可以使用@> contains array 运算符

const categories = ['category1', 'category2']

// untested code
const users = await this.usersRepository
  .createQueryBuilder('user')
  .innerJoinAndSelect('user.profile', 'profile')
  .innerJoin('profile.categories', 'categories')
  .groupBy('user.id')
  .addGroupBy('profile.id');
  .having('array_agg(categories.name::text) @> ARRAY[:...categories]', {
    categories,
  })
  .getMany();
Run Code Online (Sandbox Code Playgroud)

它不选择类别,而是将连接的类别聚合到一个数组中,并检查它是否是给定数组的超集。我无法使用 TypeORM 对此进行测试,所以我只是希望它可以处理数组构建语法,因为我在文档中的任何地方都找不到它。我希望这个解决方案对您有所帮助。

编辑:添加了缺少的 groupBy 和缺少的演员,如评论中所述。