首页 > 解决方案 > 将 csv 转换为 json 并删除重复项,同时使用 nodejs 将数据保存到 mongodb

问题描述

//产品.csv | 唯一码 | 姓名 | |:--------- | --------:| | 0001 | 鼠标 | | 0002 | 键盘 | | 0003 | 显示器 | | 0001 | 鼠标 |

//将csv转换为json并将数据保存到mongodb的代码

const csv = require("csvtojson");

router.post("/uploadProducts", async (req, res) => {
  const products = await csv().fromFile("./products.csv");
  
  try {
    products.map(async (pdata) => {
      let uniqueCode= await Product.findOne({
        product_code: pdata.productCode,
      });
      if (!uniqueCode) {
        //create new object
        let product = new Product({
          product_code: pdata.productCode,
          product_name: pdata.name,
        });
        await product.save();
      }
    });
    res.send("success");
  } catch (err) {
    console.error(err);
  }
})

在上面的代码中,我检查数据库中是否已经存在唯一代码。如果没有,则创建新对象,否则忽略该对象。所以基本上我试图在保存数据的同时删除重复项。

但这里的问题是重复项也保存在数据库中。在 products.csv 文件中,第一行的唯一代码为 0001,最后一行的唯一代码相同。因此,在映射对象时,最后一个对象应该被忽略,但事实并非如此,无论如何它都会被保存。

//一旦映射完成,那么只有数据被保存..一次。

// 创建本地数组并比较对象有效。但我想要一个可以直接与 mongodb 一起使用的解决方案。

谁能帮我这个?

标签: javascriptnode.jsjsonmongodbmongoose

解决方案


有两个问题:

  1. product.save()也是异步的,但不等待 with await。这样,如果您在随后的两行中有一个具有相同 id 的产品,很可能在处理第二行并检查数据库时Product.findOne,前一行的产品的插入尚未完成,因此防护 -检查失败,您插入另一个项目。

  2. 您向map. 每个异步函数都返回一个 Promise。这样,您map甚至可能在对 MongoDB 的任何调用到达数据库并将您的产品数组转换为运行异步的承诺数组之前就完成了。因此,您对数据库调用的执行顺序没有影响,也不能期望它们按顺序运行。这意味着,对于您的所有产品,很可能findOne在您进行任何调用之前已经调用了该函数product.save(),因此如果在调用您的过程之前它们没有在数据库中,则对于具有相同 id 的所有产品返回 false。这也意味着你发送成功在您完成整个数据库操作之前很长时间才能向客户端发送信息。

解决方案:在将 CSV 文件中的重复项发送到数据库之前,将其删除。它还将使您的程序更有效率。然后在此列表中使用您的功能,一切都会按预期工作。


推荐阅读