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

在NestJS+MongoDB中实现多筛选搜索及筛选项计数方案咨询

商品数据筛选与筛选项计数实现方案

需求描述

对MongoDB中的商品数据按字段筛选,同时返回每个筛选项的计数(例如选择特定品牌时,显示该品牌的可用数量),需要了解两种实现路径:使用Azure Search这类搜索服务,或在NestJS+MongoDB中直接实现。

数据库集合示例

[
  {
    "brand": "Screaming Eagle, The Flight",
    "producer": "Screaming Eagle",
    "productionCountry": "America",
    "region": "Napa Valley",
    "appellation": "Oakville",
    "vintage": "2016",
    "grape": "Cabernet Sauvignon",
    "maturity": "25",
    "case": "3 bottles",
    "origin": "SECONDARYMARKET",
    "type": "Red"
  },
  {
    "brand": "Joseph Phelps, Insignia",
    "producer": "Joseph Phelps",
    "productionCountry": "America",
    "region": "Napa Valley",
    "appellation": "St. Helena",
    "vintage": "2012",
    "grape": "Cabernet Sauvignon",
    "maturity": "25",
    "case": "6 bottles",
    "origin": "SECONDARYMARKET",
    "type": "Red"
  },
  {
    "brand": "Joseph Phelps, Insignia",
    "producer": "Joseph Phelps",
    "productionCountry": "America",
    "region": "Napa Valley",
    "appellation": "St. Helena",
    "vintage": "2012",
    "grape": "Cabernet Sauvignon",
    "maturity": "25",
    "case": "6 bottles",
    "origin": "SECONDARYMARKET",
    "type": "Red"
  },
  {
    "brand": "Continuum",
    "producer": "Continuum",
    "productionCountry": "America",
    "region": "Napa Valley",
    "appellation": "Oakville",
    "vintage": "2017",
    "grape": "Cabernet Sauvignon",
    "maturity": "26",
    "case": "6 bottles",
    "origin": "SECONDARYMARKET",
    "type": "Red"
  },
  {
    "brand": "Continuum",
    "producer": "Continuum",
    "productionCountry": "America",
    "region": "Napa Valley",
    "appellation": "Oakville",
    "vintage": "2017",
    "grape": "Cabernet Sauvignon",
    "maturity": "26",
    "case": "6 bottles",
    "origin": "SECONDARYMARKET",
    "type": "Red"
  }
]

实现方案

一、使用Azure Search实现

Azure Search的分面导航(Faceted Navigation) 原生支持筛选+筛选项计数的场景,是这类需求的成熟解决方案:

  • 实现步骤:
    1. 数据同步:通过Azure Data Factory或MongoDB数据源连接器,将MongoDB中的商品数据同步到Azure Search索引。
    2. 索引配置:将需要用于筛选的字段(如brand、vintage、type等)设置为可分面(Facetable) 属性。
    3. 查询请求:发起搜索时指定facet参数(例如facet=brand&facet=vintage),Azure Search会返回每个字段的不同值及其匹配文档数;结合$filter参数(如$filter=type eq 'Red'),还能返回筛选后的关联分面计数。

二、NestJS + MongoDB直接实现

方案1:MongoDB聚合管道(推荐,性能优)

利用MongoDB的聚合管道,在数据库层面完成筛选和分面计数,适合复杂筛选场景:

import { Injectable } from '@nestjs/common';
import { InjectModel } from '@nestjs/mongoose';
import { Model } from 'mongoose';
import { Product } from './schemas/product.schema';

@Injectable()
export class ProductService {
  constructor(@InjectModel(Product.name) private productModel: Model<Product>) {}

  async getFilteredProductsWithFacets(filter: Record<string, any>) {
    // 构建筛选阶段
    const matchStage = { $match: filter };

    // 分面计数与商品分页的聚合阶段
    const facetStage = {
      $facet: {
        products: [{ $skip: 0 }, { $limit: 10 }], // 可根据需求调整分页参数
        brandFacet: [
          { $group: { _id: '$brand', count: { $sum: 1 } } },
          { $sort: { count: -1 } }
        ],
        vintageFacet: [
          { $group: { _id: '$vintage', count: { $sum: 1 } } },
          { $sort: { count: -1 } }
        ],
        typeFacet: [
          { $group: { _id: '$type', count: { $sum: 1 } } }
        ]
      }
    };

    // 执行聚合查询
    const [result] = await this.productModel.aggregate([matchStage, facetStage]).exec();
    return result;
  }
}

调用示例:

// 筛选类型为Red的商品,同时返回品牌、年份的计数
const result = await this.productService.getFilteredProductsWithFacets({ type: 'Red' });
// 返回结构示例:{ products: [...], brandFacet: [{ _id: 'Joseph Phelps, Insignia', count: 2 }, ...], ... }

方案2:分步查询(适合简单场景)

如果筛选逻辑简单,可先获取筛选后的商品列表,再单独查询各字段的计数:

async getProductsWithCounts(filter: Record<string, any>) {
  // 获取筛选后的商品列表
  const products = await this.productModel.find(filter).limit(10).exec();
  
  // 查询品牌计数
  const brandCounts = await this.productModel.aggregate([
    { $match: filter },
    { $group: { _id: '$brand', count: { $sum: 1 } } }
  ]).exec();
  
  // 查询年份计数
  const vintageCounts = await this.productModel.aggregate([
    { $match: filter },
    { $group: { _id: '$vintage', count: { $sum: 1 } } }
  ]).exec();

  return {
    products,
    facets: {
      brand: brandCounts,
      vintage: vintageCounts
    }
  };
}

注意:该方案会发起多次数据库请求,数据量大时性能不如聚合管道。


内容的提问来源于stack exchange,提问作者Kelvin Nketia-Achiampong

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 23:45:43