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

使用ExpressJS、Multer、NodeJS将PDF上传至MongoDB时的问题求助

让我帮你拆解一下当前代码的问题,以及给出两种适配你需求的解决方案:

核心问题分析

你遇到的schedulePDF.myFile为undefined或存储无效的情况,主要来自这几个点:

  1. Multer配置与存储目标不匹配:你目前用Multer配合Cloudinary处理图片,但如果要把PDF存到MongoDB,Multer的存储策略需要调整——默认的Cloudinary存储会把文件传到云端,返回的req.file是云端URL等元数据,不是能直接存进MongoDB的二进制文件;如果没正确配置Multer的内存/本地存储,也拿不到文件的原始数据。
  2. Schema与数据赋值的逻辑偏差:你直接把整个req.file对象赋值给myFile,但req.file的结构和MongoDB需要的存储格式不匹配;另外你代码里的date变量如果未提前定义,name字段的默认值会报错。
  3. 路由缺少必要的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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 22:32:30