Mongoose中执行push后数组未更新问题求助
问题描述
使用Mongoose的push方法更新数组时遇到问题,localCompared数组始终显示为空;但在try-catch块里调用接口时功能正常运行。需要让数组正常更新并能在接口响应中使用。
问题代码片段
let localCompared = [] duplicate[0].map((v,i)=>{ UserDummy.find({no_hp:v.no_hp},function (err, data) { if (err) { console.log(err); return; } if (data[0]) { localCompared.push(data[0]) } }) })
完整代码
app.post("/api/users/csv", async (req, res) => { csvData = req.files.csvfile.data.toString("utf8"); return csvtojson() .fromString(csvData) .then(async (json) => { let newData = []; let user = []; let inserted = []; let duplicate = []; let localCompared = []; json.map((v, i) => { const inqueue = v.inQueue === "FALSE" || !v.inQueue || v.inQueue === "" ? false : true; const question = v.questioned === "FALSE" || v.inQueue === "" || !v.inQueue ? false : true; const id = v.id.replace("l:", ""); const newno_hp = v.no_hp .replace(/p:+62/g, "0") .replace(/p:/g, "") .replace("+62", "0"); newData.push({ id: id, nama: v.nama, durasi: v.durasi, email: v.email, created: v.created, no_hp: newno_hp, brand_name: v.brand_name, inQueue: inqueue, questioned: question, source_form: "CSV Files", isWant: "", lastContacted: "", keterangan: '', journey_step: '0', journey_status: 'basic_journey', }); }); try { const userData = await axios.get('http://localhost:3001/api/users/dummies') user.push(userData.data) } catch (error) { console.log(error); } const filteredDuplicate = newData.filter((elem)=>{ return user[0].some((ele)=>{ return ele.no_hp == elem.no_hp }) }) duplicate.push(filteredDuplicate) let filteredForInsert = new Set(user[0].map(({ no_hp })=> no_hp)) let dataforInsert = newData.filter(({no_hp})=> !filteredForInsert.has(no_hp)); inserted.push(dataforInsert) duplicate[0].map((v,i)=>{ UserDummy.find({no_hp:v.no_hp},function (err, data) { if (err) { console.log(err); return; } if (data[0]) { localCompared.push(data[0]) } }) }) if (inserted[0].length > 0) { inserted[0].map((v,i)=>{ const newUser = new UserDummy(v) newUser.save(newUser) .then((results)=>{ if (i+1 === inserted[0].length) { res.json({ done_added:`${inserted[0].length} berhasil ditambahkan!`, duplicate:`${duplicate[0].length} terdeteksi duplikat!`, data:duplicate[0], localSameData:localCompared, }) } }).catch((err)=>{ console.log(err); }) }) }else{ res.json({ done_added:`Tidak ada data yang ditambahkan!`, duplicate:`${duplicate[0].length} terdeteksi duplikat!`, data:duplicate[0], localSameData:localCompared, }) } }); });
解决方案
问题核心是异步操作时序不匹配:
UserDummy.find()是异步方法,用回调处理结果时,代码会直接执行后续响应逻辑,不会等待所有查询完成。当返回响应时,所有find操作还未执行完毕,因此localCompared数组为空。- 而try-catch里的
axios.get用了await,会等待请求完成后再继续执行,所以能正常获取数据。
修复步骤
- 将
UserDummy.find()改为Promise形式,用Promise.all()批量处理所有异步查询,确保所有操作完成后再处理响应。 - 替换低效的逐个
save逻辑,改用批量保存提升性能。
修改后的关键代码片段
// 替换原有的duplicate.map逻辑,生成所有查询Promise const comparePromises = duplicate[0].map(v => { return UserDummy.findOne({ no_hp: v.no_hp }) // 用findOne替代find,更贴合需求 .catch(err => { console.log(err); return null; // 出错时返回null,不影响后续结果处理 }); }); // 等待所有查询完成 const comparedResults = await Promise.all(comparePromises); // 过滤无效值,填充localCompared数组 localCompared = comparedResults.filter(item => item !== null);
完整修复后的接口代码
app.post("/api/users/csv", async (req, res) => { try { const csvData = req.files.csvfile.data.toString("utf8"); const json = await csvtojson().fromString(csvData); let newData = []; let user = []; let inserted = []; let duplicate = []; let localCompared = []; json.forEach((v, i) => { const inqueue = v.inQueue === "FALSE" || !v.inQueue || v.inQueue === "" ? false : true; const question = v.questioned === "FALSE" || !v.questioned || v.questioned === "" ? false : true; // 修复原代码中误写的v.inQueue判断 const id = v.id.replace("l:", ""); const newno_hp = v.no_hp .replace(/p:+62/g, "0") .replace(/p:/g, "") .replace("+62", "0"); newData.push({ id: id, nama: v.nama, durasi: v.durasi, email: v.email, created: v.created, no_hp: newno_hp, brand_name: v.brand_name, inQueue: inqueue, questioned: question, source_form: "CSV Files", isWant: "", lastContacted: "", keterangan: '', journey_step: '0', journey_status: 'basic_journey', }); }); const userData = await axios.get('http://localhost:3001/api/users/dummies'); user.push(userData.data); const filteredDuplicate = newData.filter((elem) => { return user[0].some((ele) => ele.no_hp === elem.no_hp); }); duplicate.push(filteredDuplicate); const filteredForInsert = new Set(user[0].map(({ no_hp }) => no_hp)); const dataforInsert = newData.filter(({ no_hp }) => !filteredForInsert.has(no_hp)); inserted.push(dataforInsert); // 批量处理重复数据查询 const comparePromises = duplicate[0].map(v => { return UserDummy.findOne({ no_hp: v.no_hp }) .catch(err => { console.log(err); return null; }); }); const comparedResults = await Promise.all(comparePromises); localCompared = comparedResults.filter(item => item !== null); if (inserted[0].length > 0) { // 批量保存新用户,提升效率 const savePromises = inserted[0].map(v => new UserDummy(v).save()); await Promise.all(savePromises); res.json({ done_added: `${inserted[0].length} berhasil ditambahkan!`, duplicate: `${duplicate[0].length} terdeteksi duplikat!`, data: duplicate[0], localSameData: localCompared, }); } else { res.json({ done_added: `Tidak ada data yang ditambahkan!`, duplicate: `${duplicate[0].length} terdeteksi duplikat!`, data: duplicate[0], localSameData: localCompared, }); } } catch (error) { console.log(error); res.status(500).json({ error: "Internal server error" }); } });
额外优化点
- 用
findOne替代find,仅查询匹配的第一个文档,减少不必要的数据传输。 - 新增全局
try-catch,统一处理接口内的所有错误,避免未捕获异常导致服务崩溃。 - 修复原代码中
question变量的判断bug(误将v.questioned写成v.inQueue)。
内容的提问来源于stack exchange,提问作者Sahrul Ramdan
相关产品推荐
相关产品推荐

