Mongoose遍历ID数组校验存在性返回空数组的解决方法
问题原因
Array.map本身不感知内部异步函数的执行状态,当前写法中所有数据库查询的异步操作还没执行完成,就直接同步返回了初始为空的existingProductId数组,所以打印结果永远是空。- 缺少Mongoose ID格式前置校验:如果传入格式不合法的ID,
Product.findById会直接抛出异常,中断整个执行流程。 - 异步逻辑没有被正确等待:包含
await的函数本身会返回Promise,用同步方式直接接收返回值,拿到的不是最终执行完成的结果。
解决方案
基础修复版(保留原有遍历逻辑)
将函数改为异步函数,用Promise.all等待所有遍历中的异步查询执行完成后再返回结果,同时加上ID合法性校验:
const mongoose = require('mongoose'); async function returnValidId(products){ const existingProductId = []; // 等待所有异步查询执行完毕 await Promise.all( products.map(async(product)=>{ // 前置校验ID格式,非法ID直接跳过 if(!mongoose.isValidObjectId(product.productId)) return; const existingProduct = await Product.findById(product.productId); if(existingProduct){ existingProductId.push({id: existingProduct._id}); } }) ); return existingProductId; } // 调用异步函数需要用await(需在async上下文内)或.then接收结果 const data = await returnValidId(products); console.log(data);
性能优化版(推荐)
循环单条查询数据库会产生多次数据库交互,性能较差,可以先提取所有格式合法的ID,用$in操作符一次性查询所有存在的记录,大幅提升执行效率:
const mongoose = require('mongoose'); async function returnValidId(products){ // 提取所有格式合法的productId const validFormatIds = products .map(item => item.productId) .filter(id => mongoose.isValidObjectId(id)); // 一次性查询所有存在的产品记录,只查询_id字段减少数据传输 const existingProducts = await Product.find({ _id: { $in: validFormatIds } }).select('_id'); // 组装为要求的格式返回 return existingProducts.map(product => ({id: product._id})); } // 调用方式和基础版一致 const data = await returnValidId(products); console.log(data);
内容的提问来源于stack exchange,提问作者Godwin Ehikhamhen
相关产品推荐
相关产品推荐

