You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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;
}

逻辑说明

  1. innerJoin:关联商品与属性值表,仅保留存在属性值关联的商品;若需保留无属性值的商品,可替换为leftJoin。
  2. where条件:筛选出属性值ID在目标列表中的记录。
  3. groupBy:按商品ID分组,将同一商品的所有匹配属性值归为一组。
  4. having条件:统计每组内不同属性值的数量,只有数量等于传入ID列表长度时,才判定该商品包含所有指定属性值。
  5. leftJoinAndSelect:可选操作,若需返回的商品对象包含完整属性值数据,可添加该方法。

内容的提问来源于stack exchange,提问作者Viktor

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 12:15:56