MongoDB聚合$match表达式中使用$cond实现可选条件动态查询
MongoDB可选尺码筛选聚合实现方案
核心需求
- 传入
selectedSize参数时,仅返回匹配对应分类、子分类、指定尺码的商品 - 未传入
selectedSize(值为null)时,跳过尺码校验,返回所有匹配分类、子分类的商品
方案1:JS层动态构造匹配条件(优先推荐)
这是生产环境最常用的写法,查询性能最优,可以命中数据库索引,逻辑维护成本低:
// 初始化固定必传的筛选条件 const matchStage = { "product.category": req.body.selectedCategory, "product.subCategory": req.body.selectedSubCategory }; // 仅当尺码参数为有效值时,追加尺码过滤规则 if (req.body.selectedSize !== null && req.body.selectedSize !== undefined) { matchStage["product.size"] = req.body.selectedSize; } // 执行聚合查询 const searchResults = await user.aggregate([ { $match: matchStage } // 后续可追加分页、排序、投影等其他聚合阶段 ]);
该方案优势:
- 避免在聚合表达式中写冗余判断,代码可读性高
$match阶段的等值查询条件可以命中集合上的普通索引,大数据量下查询速度远高于$expr写法- 不会出现聚合表达式语法写错导致的匹配异常
方案2:聚合管道内写条件判断(仅作语法参考)
如果必须把所有判断逻辑放在聚合管道内部实现,注意$expr下的$cond需要返回布尔值作为匹配依据,不能直接返回查询对象,修正后的代码如下:
const searchResults = await user.aggregate([ { $match: { "product.category": req.body.selectedCategory, "product.subCategory": req.body.selectedSubCategory, $expr: { $cond: { // 判断是否传入了有效尺码参数 if: { $ne: [req.body.selectedSize, null] }, // 传了尺码:校验文档size字段和传入值是否相等,相等则保留文档 then: { $eq: ["$product.size", req.body.selectedSize] }, // 没传尺码:直接返回true,所有文档都满足尺码条件 else: true } } } } ]);
原代码错误说明
$cond的then/else分支需要返回布尔判断结果,原代码直接写{ product.size: xxx }的对象格式不符合聚合表达式语法- 原代码else分支写
{ product.size: "" }会强制匹配size为空的商品,完全不符合“跳过尺码筛选”的需求 - 不要给请求参数强行套模板字符串,否则null值会被转为字符串
"null",导致条件判断逻辑失效
内容的提问来源于stack exchange,提问作者Sb Zakaria
相关产品推荐
相关产品推荐

