Mongoose从CSV导入数据到MongoDB Atlas仅插部分数据报错如何解决
问题原因
- 响应重复发送:你在for循环的单条保存回调里调用
res.render,第一条数据保存成功后就已经向客户端返回了响应,后续保存成功再调用该方法就会触发ERR_HTTP_HEADERS_SENT报错,同时打断未完成的保存操作,导致数据插入不全。 - 文件上传逻辑缺失:express原生不解析
multipart/form-data格式的文件上传请求,直接从req.body.file拿不到上传的CSV文件路径,需要配合文件上传中间件处理。 - 异步逻辑混乱:async/await和then混用,且单条循环保存数据库的操作没有做异步等待,逻辑执行顺序不可控。
修复方案
首先安装文件上传依赖multer:
npm install multer
修改后的完整代码如下:
const csvtojson = require("csvtojson"); const express = require("express"); const bodyParser = require("body-parser"); const ejs = require("ejs"); const mongoose = require("mongoose"); const multer = require('multer'); const Student = require("./models/student"); const encrypt = require("mongoose-encryption") const app = express(); // 配置multer临时存储上传的文件 const upload = multer({ dest: 'uploads/' }) app.use(express.static("public")); app.set("views", "./views"); app.set("view engine", "ejs"); app.use( bodyParser.urlencoded({ extended: true, }) ); try { mongoose.connect( process.env.URL, { useNewUrlParser: true, useUnifiedTopology: true }, () => console.log("Mongoose connected") ); } catch (e) { console.log("Failed to connect to mongoose!"); } app.get("/test", function (req, res) { res.render("test"); }); // 用multer中间件接收name为file的上传文件 app.post("/test", upload.single('file'), async function (req, res) { try { // 拿到上传后的临时文件路径 const csvfilepath = req.file.path; // 转换csv为json const jsonArr = await csvtojson().fromFile(csvfilepath); // 批量插入数据,比循环单条插入效率高很多 await Student.insertMany(jsonArr.map(item => ({ fname: item.fname, // 注意这里如果csv里姓的列名是lname就改成item.lname,别写错字段 lname: item.nlame, prn: item.prn, username: item.email, password: item.password, department: item.department, year: item.year, batch: item.batch, placement_Status: item.placement_Status }))); // 所有数据插入完成后再返回响应 res.render("test"); } catch (err) { console.log("操作失败:", err); res.status(500).send("数据导入失败"); } }); app.listen(3000, function () { console.log("Server started on port 3000..."); });
额外注意事项
- 前端提交CSV的表单需要添加
enctype="multipart/form-data"属性,示例表单代码:
<form action="/test" method="post" enctype="multipart/form-data"> <input type="file" name="file" accept=".csv"> <button type="submit">上传</button> </form>
- 请确认CSV文件的列名和代码中映射的字段名完全一致,避免出现字段为空的情况。
- 如果需要对导入失败的数据做单独处理,可以在insertMany的参数中添加
{ordered: false}配置,这样单条数据插入失败不会打断整体导入流程,后续可以拿到错误列表单独处理。
内容的提问来源于stack exchange,提问作者Tejas Sawant
相关产品推荐
相关产品推荐

