基于MongoDB检测已存在shortid并生成新唯一ID的函数返回undefined问题
问题根因
你写的函数最终返回undefined,核心原因是MongoDB的findOne是异步IO操作,回调内的返回值无法穿透到外层函数的返回上下文:
- 外层
generateshortid执行时,生成初始myid后就会发起数据库查询,因为查询是异步等待结果的,外层函数不会阻塞等待查询返回,会直接执行到函数末尾——整个外层函数没有设置任何显式返回值,天然会返回undefined - 你写在
findOne回调里的return newid、return myid,仅会把值返回给这个匿名回调函数本身,根本不会作为外层generateshortid的返回值,属于无效返回 - 现有逻辑本身存在漏洞:哪怕回调能把值传出去,检测到ID重复后仅重新生成一次
newid,完全没有校验这个新ID是否也在数据库中存在,无法100%保证最终返回的是不重复ID
修正实现
现在主流的Mongoose模型(也就是你代码里的Note)已经默认支持Promise调用,直接用async/await写法就能解决异步返回的问题,同时补上循环校验的逻辑保证ID唯一性:
async function generateshortid() { // 循环校验直到拿到数据库中不存在的ID while (true) { const candidateId = shortid.generate(); // 等待查询结果返回,lean()可以减少查询的文档对象序列化开销 const existRecord = await Note.findOne({ shortid: candidateId }).lean(); // 查不到占用记录就直接返回这个ID if (!existRecord) { return candidateId; } } }
调用这个函数时,需要配合await获取最终的合法ID,不能同步直接取值:
// 调用示例 const validShortId = await generateshortid();
如果一定要兼容传统回调风格的写法,需要把校验逻辑递归、把结果透传到最外层的回调,避免嵌套断层:
// 回调风格写法(不推荐,维护成本高) function generateshortid(callback) { const candidateId = shortid.generate(); Note.findOne({ shortid: candidateId }, (err, existData) => { if (err) return callback(err); // 发现ID重复就递归重新生成,直到拿到不重复的结果 if (existData) return generateshortid(callback); // 校验通过就把合法ID返回给调用方 callback(null, candidateId); }); }
内容的提问来源于stack exchange,提问作者Valor
相关产品推荐
相关产品推荐

