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)
我只想要category1
ANDcategory2
作为配置文件的多对多关系的名称出现的用户。通过上面的查询,我还收到仅其中一个值作为名称出现的用户。以我目前的结构来说这可能吗?
这与我的接近,但 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)
如果您使用 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 和缺少的演员,如评论中所述。