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

Multer+csv-to-json同时上传文件至本地与MongoDB故障求助

问题分析与解决方案

我帮你排查了代码里的几个关键问题,这就是为什么MongoDB导入功能没正常工作的原因:


1. 函数定义顺序错误

你在mongoClient.connect的回调里调用了insertDocuments,但这个函数是用const声明在回调之后的。const声明的变量没有变量提升,所以当代码执行到insertDocuments(db, function() { ... })的时候,这个函数还没被定义,直接会抛出引用错误,导致后续的MongoDB操作根本没执行。

2. 全局filename的并发冲突

你用了全局变量filename来存储上传后的文件名,如果同时有两个用户上传文件,后一个请求会覆盖这个变量的值,导致前一个请求读取错误的文件路径。

3. 多次发送HTTP响应

你在csv()的on('json')回调里调用res.redirect('/'),这意味着每解析CSV的一行数据,就会尝试给客户端发送一次重定向响应。HTTP协议要求一个请求只能对应一个响应,这会导致Cannot set headers after they are sent to the client的错误,而且程序会提前终止。

4. 过时的MongoDB API调用

你用的collection.insert()方法已经被废弃了,应该使用insertOne()(单条插入)或者insertMany()(批量插入);另外,新版的MongoDB Node.js客户端在connect回调里返回的是client对象,而不是直接的db,需要通过client.db()来获取数据库实例。


修改后的完整代码

后端JavaScript代码

var express = require('express');
var multer = require('multer');
const csv = require('csvtojson');
const mongoClient = require('mongodb').MongoClient;
const assert = require('assert');

var app = express();

// 配置Multer存储,不再使用全局filename,而是从req.file里获取
var storage = multer.diskStorage({
    destination: function(req, file, cb) {
        cb(null, 'uploads/')
    },
    filename: function(req, file, cb) {
        const filename = Date.now() + '-' + file.originalname;
        cb(null, filename);
        console.log('上传的文件名:', filename);
    }
})

var upload = multer({ storage: storage })

app.get('/', (req, res) => {
    res.sendFile(__dirname + '/index.html');
});

// 把insertDocuments提到前面,确保调用时已经定义
const insertDocuments = (db, csvFilePath, res) => {
    let collection = db.collection('uploaded');
    // 先把所有CSV数据转成JSON数组,再批量插入,效率更高
    csv()
        .fromFile(csvFilePath)
        .then((jsonArray) => {
            // 使用insertMany批量插入,替代过时的insert方法
            collection.insertMany(jsonArray)
                .then(() => {
                    console.log('所有数据已成功插入MongoDB');
                    res.redirect('/');
                })
                .catch((err) => {
                    console.error('插入数据时出错:', err);
                    res.status(500).send('数据插入失败');
                });
        })
        .catch((err) => {
            console.error('读取CSV文件时出错:', err);
            res.status(500).send('读取CSV文件失败');
        });
}

app.post('/', upload.single('file-to-upload'), function(req, res, next) {
    // 从req.file里获取上传后的文件信息,避免全局变量冲突
    if (!req.file) {
        return res.status(400).send('请选择要上传的文件');
    }
    const csvFilePath = 'uploads/' + req.file.filename;
    console.log('要导入的CSV路径:', csvFilePath);

    const url = 'mongodb://localhost:27017/csvfilereader';
    mongoClient.connect(url)
        .then((client) => {
            console.log("已成功连接到MongoDB服务器");
            const db = client.db('csvfilereader'); // 获取数据库实例
            insertDocuments(db, csvFilePath, res);
            client.close();
        })
        .catch((err) => {
            console.error('连接MongoDB失败:', err);
            res.status(500).send('数据库连接失败');
        });
});

app.listen(3200, () => {
    console.log('服务器运行在http://localhost:3200');
});

HTML代码(无需修改,保持原样)

<html lang="en">
<head>
    <title>Simple Multer Upload Example</title>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
    <form action="/" enctype="multipart/form-data" method="post">
        <input type="file" name="file-to-upload">
        <input type="submit" value="Upload">
    </form>
</body>
</html>

关键改进点说明

  • 移除了全局filename变量,改用req.file.filename获取上传后的文件名,避免并发请求冲突
  • 将insertDocuments函数提前定义,确保调用时已经存在
  • 使用csv().fromFile().then()的Promise方式替代事件监听,代码更简洁,并且在所有数据解析完成后一次性批量插入MongoDB,效率更高
  • 更新了MongoDB的API调用:使用insertMany()替代过时的insert(),并且正确处理client对象获取数据库实例
  • 统一处理错误情况,给客户端返回合适的HTTP状态码和提示信息
  • 确保只在所有操作完成后发送一次响应(重定向或错误信息)

这样修改后,Multer的本地上传和MongoDB的导入功能就都能正常工作了。

内容的提问来源于stack exchange,提问作者Monkey D. Luffy

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.12 04:16:42