You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 14:48:14