如何在Firebase Functions中从Firestore获取排除指定值的随机数据
现有代码问题梳理
- 语法逻辑缺陷:混用
async/await与.then()链式调用,写法冗余;catch块中调用的json()未定义,也没有返回错误响应,调用方无法捕获异常 - 性能问题:会拉取所有符合
companyName != 指定值的全量文档,当集合数据量较大时会严重浪费带宽与内存资源 - 功能缺失:未实现随机取数逻辑,仅返回了所有符合条件的公司数组
优化实现方案
1. 小数据量场景优化(单集合文档数<1000适用)
直接修正写法,拿到全量符合条件的数组后通过洗牌算法取随机值:
async function selectRandomCompany(excludeCompanyName, count = 1) { try { // 直接用await获取查询结果,去掉冗余.then嵌套 const querySnapshot = await db.collection('companies') .where('companyName', '!=', excludeCompanyName) .get(); // 简化数组构造,不用手动push const validCompanies = querySnapshot.docs.map(doc => doc.data()); if (validCompanies.length === 0) return []; // Fisher-Yates 洗牌算法打乱数组,取指定数量的随机项 for (let i = validCompanies.length - 1; i > 0; i--) { const j = Math.floor(Math.random() * (i + 1)); [validCompanies[i], validCompanies[j]] = [validCompanies[j], validCompanies[i]]; } return validCompanies.slice(0, count); } catch (error) { // 修正错误返回,可根据业务需求调整返回格式 throw new Error(error.message); } }
2. 大数据量场景优化(单集合文档数>1000适用)
避免全表扫描,提前给companies集合的所有文档新增一个数值类型的随机字段randomSeed,写入时取值范围为0~1,查询时直接按随机字段过滤,限制返回条数:
async function selectRandomCompany(excludeCompanyName, count = 1) { try { const randomPoint = Math.random(); // 先从随机点往后查 let query = db.collection('companies') .where('companyName', '!=', excludeCompanyName) .where('randomSeed', '>=', randomPoint) .orderBy('randomSeed') .limit(count); let querySnapshot = await query.get(); let result = querySnapshot.docs.map(doc => doc.data()); // 如果查到的数量不够,再从随机点前面补 if (result.length < count) { query = db.collection('companies') .where('companyName', '!=', excludeCompanyName) .where('randomSeed', '<', randomPoint) .orderBy('randomSeed') .limit(count - result.length); querySnapshot = await query.get(); result = result.concat(querySnapshot.docs.map(doc => doc.data())); } return result; } catch (error) { throw new Error(error.message); } }
该方案只会拉取你需要的count条数据,不需要扫描全表,性能提升非常明显。
内容的提问来源于stack exchange,提问作者Irfana
相关产品推荐
相关产品推荐

