如何在Express路由中实现从数据库调取12-15个不重复随机商品
实现方案
你可以直接使用MongoDB原生的$sample聚合操作符实现需求,该操作符可以从匹配的数据集里随机返回指定数量的不重复文档,性能最优,适配绝大多数场景:
方案1:MongoDB $sample 聚合(推荐)
router.get("/alw", function(req, res){ // 生成12~15之间的随机整数,包含边界值 const fetchCount = Math.floor(Math.random() * 4) + 12; Product.aggregate([ // 先过滤分类为alw的商品 { $match: { category: "alw" } }, // 随机取出fetchCount个不重复的商品 { $sample: { size: fetchCount } } ], function(err, products){ if (err){ console.log(err); return res.status(500).send("数据查询失败"); } res.render("products/alw", {products: products}); }); });
优势:
- 数据库层面直接完成随机筛选,性能远高于全量查询后再做数据处理,哪怕分类下有数十万条商品也不会有性能问题
- 原生保证返回的商品无重复,不需要额外写去重逻辑
- 代码简洁易维护
方案2:全量查询后洗牌(仅适用于分类下商品总数<1000的场景)
如果你使用的MongoDB版本低于3.2不支持$sample,可以全量查询后用Fisher-Yates洗牌算法打乱数组再截取:
router.get("/alw", function(req, res){ Product.find({"category": "alw"}, function(err, allProduct){ if (err){ console.log(err); return res.status(500).send("数据查询失败"); } // Fisher-Yates 洗牌算法打乱数组,保证完全随机 for (let i = allProduct.length - 1; i > 0; i--) { const j = Math.floor(Math.random() * (i + 1)); [allProduct[i], allProduct[j]] = [allProduct[j], allProduct[i]]; } // 生成随机取数数量,兼容分类下商品不足12的边界情况 const fetchCount = Math.min(Math.floor(Math.random() * 4) + 12, allProduct.length); const randomProducts = allProduct.slice(0, fetchCount); res.render("products/alw", {products: randomProducts}); }); });
内容的提问来源于stack exchange,提问作者Kingdavid Oshin
相关产品推荐
相关产品推荐

