如何在PostgreSQL中筛选包含全部指定属性值ID的商品?
问题描述
我正在使用TypeORM查询构建器筛选商品,现有实体定义如下:
Product实体
@Entity() export class Product extends MedusaProduct { @ManyToMany(() => AttributeValue) @JoinTable() attribute_values: AttributeValue[]; }
AttributeValue实体
@Entity() export class AttributeValue extends BaseEntity { @Column({ nullable: true }) value: string; @ManyToOne(() => Attribute, (a) => a.values) attribute: Attribute; @Column({ type: "jsonb", nullable: true }) metadata: Record<string, unknown>; @Column({ type: "boolean", default: false }) is_bool: boolean; @Column({ type: "int" }) rank: number; @BeforeInsert() private beforeInsert(): void { this.id = generateEntityId(this.id, "attr_val"); } }
我的需求是根据属性值ID列表筛选商品,要求商品必须包含列表中的所有属性值,示例如下:
商品列表:
product-1 属性值ID: [1,2,3,4]
product-2 属性值ID: [3,4]
product-3 属性值ID: [1,2]
预期筛选结果:
传入属性列表 [1,2] → 返回 [product-1, product-3]
传入属性列表 [1,2,3,4] → 返回 [product-1]
传入属性列表 [3,4] → 返回 [product-1, product-2]
我尝试过使用IN运算符,但它的逻辑是OR(只要包含其中一个就匹配),无法满足“必须包含所有指定属性值”的需求。
解决方案
要实现“商品必须包含所有指定属性值ID”的筛选逻辑,需要结合GROUP BY和HAVING COUNT统计匹配的属性数量,确保数量等于传入的ID列表长度。以下是TypeORM查询构建器的实现代码:
import { getRepository } from "typeorm"; import { Product } from "./path-to-product.entity"; async function filterProductsByAttributeValueIds(attributeValueIds: string[]) { const productRepository = getRepository(Product); // 空列表处理,可根据业务需求调整逻辑 if (attributeValueIds.length === 0) { return productRepository.find({ relations: ["attribute_values"] }); } const products = await productRepository .createQueryBuilder("product") // 关联属性值表,仅保留有匹配属性的商品 .innerJoin("product.attribute_values", "attr_val") // 筛选属性值ID在目标列表中的记录 .where("attr_val.id IN (:...attributeValueIds)", { attributeValueIds }) // 按商品ID分组 .groupBy("product.id") // 确保分组后匹配的属性值数量等于目标列表长度(即所有属性都匹配) .having("COUNT(DISTINCT attr_val.id) = :idCount", { idCount: attributeValueIds.length }) // 可选:加载商品关联的所有属性值数据 .leftJoinAndSelect("product.attribute_values", "product_attr_vals") .getMany(); return products; }
逻辑说明
innerJoin:关联商品与属性值表,仅保留存在属性值关联的商品;若需保留无属性值的商品,可替换为leftJoin。where条件:筛选出属性值ID在目标列表中的记录。groupBy:按商品ID分组,将同一商品的所有匹配属性值归为一组。having条件:统计每组内不同属性值的数量,只有数量等于传入ID列表长度时,才判定该商品包含所有指定属性值。leftJoinAndSelect:可选操作,若需返回的商品对象包含完整属性值数据,可添加该方法。
内容的提问来源于stack exchange,提问作者Viktor
相关产品推荐
相关产品推荐

