使用ExpressJS、Multer、NodeJS将PDF上传至MongoDB时的问题求助
让我帮你拆解一下当前代码的问题,以及给出两种适配你需求的解决方案:
核心问题分析
你遇到的schedulePDF.myFile为undefined或存储无效的情况,主要来自这几个点:
- Multer配置与存储目标不匹配:你目前用Multer配合Cloudinary处理图片,但如果要把PDF存到MongoDB,Multer的存储策略需要调整——默认的Cloudinary存储会把文件传到云端,返回的
req.file是云端URL等元数据,不是能直接存进MongoDB的二进制文件;如果没正确配置Multer的内存/本地存储,也拿不到文件的原始数据。 - Schema与数据赋值的逻辑偏差:你直接把整个
req.file对象赋值给myFile,但req.file的结构和MongoDB需要的存储格式不匹配;另外你代码里的date变量如果未提前定义,name字段的默认值会报错。 - 路由缺少必要的Multer中间件:虽然你说
req.file能被检测到,但如果路由上没挂载upload.single('xxx')中间件,req.file根本不会存在,这一点要再确认。
方案1:直接将PDF二进制数据存储到MongoDB
如果你的核心需求是把PDF文件本身存在MongoDB里,按以下步骤调整:
1. 配置Multer为内存存储
先让Multer把上传的文件临时存在内存中,这样能拿到文件的二进制buffer:
const multer = require('multer'); const storage = multer.memoryStorage(); // 指定上传的文件字段名(要和前端表单的name属性一致,比如前端是<input type="file" name="pdfFile">) const upload = multer({ storage: storage });
2. 优化Schema结构
用MongoDB原生支持的Buffer类型存储二进制数据,同时增加MIME类型字段方便后续下载:
const schedulePDFSchema = new mongoose.Schema({ name: { type: String, // 修正默认值的date变量问题,用new Date()生成当前日期 default: `SchedulePDF - ${new Date().toDateString()}` }, myFile: { type: Buffer, // 明确存储二进制数据 required: true }, contentType: { type: String, // 存储文件的MIME类型(比如application/pdf) required: true } });
3. 修正POST路由代码
在路由上挂载Multer中间件,然后把req.file里的buffer和MIME类型赋值给Schema:
// 注意要把upload.single('pdfFile')放在权限中间件前面 router.post("/schedulePDF", upload.single('pdfFile'), isLoggedin, isAdmin, async(req,res)=>{ try { if (!req.file) { req.flash('error', '请选择要上传的PDF文件'); return res.redirect('/dash'); } const schedulePDF = new SchedulePDFModel({ // 可以用原文件名替代默认值,更友好 name: req.file.originalname || `SchedulePDF - ${new Date().toDateString()}`, myFile: req.file.buffer, contentType: req.file.mimetype }); await schedulePDF.save(); req.flash('success', 'PDF文件上传成功!'); res.redirect('/dash'); } catch (err) { req.flash('error', `上传失败:${err.message}`); res.redirect('/dash'); } });
方案2:PDF存Cloudinary,仅URL存MongoDB(更推荐)
MongoDB并不适合存储大文件,更优的做法是继续用Cloudinary存储PDF,只把云端URL存到MongoDB:
1. 确保Cloudinary的Multer配置正确
const cloudinary = require('cloudinary').v2; const { CloudinaryStorage } = require('multer-storage-cloudinary'); const multer = require('multer'); cloudinary.config({ cloud_name: '你的Cloudinary云名称', api_key: '你的API密钥', api_secret: '你的API密钥' }); const storage = new CloudinaryStorage({ cloudinary: cloudinary, params: { folder: 'schedule-pdfs', // 自定义Cloudinary中的存储文件夹 allowed_formats: ['pdf'] // 只允许上传PDF } }); const upload = multer({ storage: storage });
2. 修改Schema存储URL
const schedulePDFSchema = new mongoose.Schema({ name: { type: String, default: `SchedulePDF - ${new Date().toDateString()}` }, pdfUrl: { type: String, // 存储Cloudinary返回的PDF文件URL required: true }, originalName: { type: String // 可选:存储原文件名,方便用户识别 } });
3. 修正路由代码
此时req.file.path就是Cloudinary返回的文件URL,直接存入MongoDB即可:
router.post("/schedulePDF", upload.single('pdfFile'), isLoggedin, isAdmin, async(req,res)=>{ try { if (!req.file) { req.flash('error', '请选择要上传的PDF文件'); return res.redirect('/dash'); } const schedulePDF = new SchedulePDFModel({ name: req.file.originalname || `SchedulePDF - ${new Date().toDateString()}`, pdfUrl: req.file.path, originalName: req.file.originalname }); await schedulePDF.save(); req.flash('success', 'PDF文件上传成功!'); res.redirect('/dash'); } catch (err) { req.flash('error', `上传失败:${err.message}`); res.redirect('/dash'); } });
内容的提问来源于stack exchange,提问作者TheodosisKats
相关产品推荐
相关产品推荐

