基于Express+MongoDB实现多颜色多尺码商品筛选API改造
实现多颜色/多尺码的商品筛选功能(Express+MongoDB)
现有基于Express和MongoDB搭建的服装商城后端,getAllProducts接口当前无法支持多颜色(如请求参数color=green,blue)和多尺码(如size=26,28)的筛选需求,以下是改造后的完整实现方案:
原问题代码回顾
原getAllProducts接口
const getAllProducts = async (req: Request, res: Response) => { const { page, limit, search, color, size, category, brand } = req?.query; let currentPage = Number(page) || 0; let docLimit = Number(limit) || 10; let searchDoc = search || ''; try { const products = await Product.aggregate([ { $lookup: { from: 'stores', localField: 'store', foreignField: '_id', as: 'store', }, }, { $match: { $or: [ { title: { $regex: searchDoc, $options: 'i' }, }, { 'store.name': { $regex: searchDoc, $options: 'i' }, }, ], ...(color ? { color: { $regex: color, $options: 'i' } } : {}), ...(brand ? { 'store.name': { $regex: brand, $options: 'i' } } : {}), ...(size ? { size: { $in: [Number(size)], }, } : {}), ...(category ? { $expr: { $eq: ['$category', category] } } : {}), }, }, { $skip: currentPage * docLimit, }, { $limit: docLimit, }, ]); const total = await Product.find().countDocuments(); const data = { products, total, }; res.status(200).json({ statusCode: 200, success: true, message: 'fetch successfully', data, }); } catch (error) { if (error instanceof Error) { res.status(500).json({ statusCode: 500, success: false, message: error.message, error, }); } } };
Product Schema
const productSchema = new mongoose.Schema<IProduct>( { title: { type: String, required: true, }, description: { type: String, }, color: { type: [String], required: true, enum: [ 'black', 'white', 'blue', 'brown', 'copper', 'gold', 'green', 'grey', 'navy', 'pink', 'orange', ], }, price: { type: Number, required: true, }, discount: { type: Number, default: 0, }, rating: { type: Number, default: 0, }, category: { type: String, enum: [ 'shirts', 'jeans', 'jacket', 'top', 'skirts', 'pants', 'dresses', 't-shirts', 'hats', 'socks', ], }, store: { type: mongoose.Schema.Types.ObjectId, ref: 'stores', }, size: { type: [Number], }, quantity: { type: Number, default:5 }, productImg: [ { src: { type: String, }, }, ], }, { timestamps: true } );
改造后的实现代码
const getAllProducts = async (req: Request, res: Response) => { const { page, limit, search, color, size, category, brand } = req?.query; let currentPage = Number(page) || 0; let docLimit = Number(limit) || 10; let searchDoc = search || ''; // 构建统一的筛选条件对象 const matchConditions: any = { $or: [ { title: { $regex: searchDoc, $options: 'i' } }, { 'store.name': { $regex: searchDoc, $options: 'i' } } ] }; // 处理多颜色筛选:分割参数为数组,用$in匹配 if (color) { const colorArray = (color as string).split(',').map(c => c.trim().toLowerCase()); matchConditions.color = { $in: colorArray }; } // 处理多尺码筛选:分割参数为数字数组,用$in匹配 if (size) { const sizeArray = (size as string).split(',').map(s => Number(s.trim())).filter(num => !isNaN(num)); matchConditions.size = { $in: sizeArray }; } // 品牌筛选 if (brand) { matchConditions['store.name'] = { $regex: brand as string, $options: 'i' }; } // 分类筛选 if (category) { matchConditions.category = category as string; } try { const products = await Product.aggregate([ { $lookup: { from: 'stores', localField: 'store', foreignField: '_id', as: 'store', }, }, { $match: matchConditions }, { $skip: currentPage * docLimit }, { $limit: docLimit }, ]); // 复用筛选条件计算准确的总条数 const total = await Product.aggregate([ { $lookup: { from: 'stores', localField: 'store', foreignField: '_id', as: 'store' } }, { $match: matchConditions }, { $count: 'total' } ]).then(result => result[0]?.total || 0); const data = { products, total, }; res.status(200).json({ statusCode: 200, success: true, message: '获取成功', data, }); } catch (error) { if (error instanceof Error) { res.status(500).json({ statusCode: 500, success: false, message: error.message, error, }); } } };
关键改动说明
多颜色参数处理
- 将逗号分隔的
color参数分割为数组,统一转小写匹配Schema枚举值,使用MongoDB的$in操作符匹配商品颜色数组中包含任一指定颜色的文档,替换原低效的正则匹配。
- 将逗号分隔的
多尺码参数处理
- 分割
size参数为数组,转换为数字类型并过滤无效值,用$in操作符匹配商品尺码数组中包含任一指定尺码的文档,修复原仅支持单个尺码的问题。
- 分割
总条数计算修复
- 原代码直接统计所有商品总数,与筛选后分页数据不匹配。改造后复用聚合管道的筛选条件,通过
$count获取准确的筛选后总条数。
- 原代码直接统计所有商品总数,与筛选后分页数据不匹配。改造后复用聚合管道的筛选条件,通过
筛选条件重构
- 将分散的筛选逻辑整合到
matchConditions对象中,代码更清晰易维护。
- 将分散的筛选逻辑整合到
内容的提问来源于stack exchange,提问作者Marchant Khalid
相关产品推荐
相关产品推荐

