You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Mongoose连接超时问题:上传媒体文件至MongoDB时元数据无法保存

问题排查与解决方案

嘿,我来帮你搞定这个问题!你碰到的mediainfos.insertOne()缓冲超时问题,核心原因其实是你的文件详情模型和GridFS用的不是同一个MongoDB连接,导致模型没法正常写入数据库,一直等到超时。

问题根源拆解

你用mongoose.createConnection()创建了一个独立连接conn来处理GridFS文件上传,但你的mediaInfo模型是通过Mongoose.model()注册的——它默认绑定的是Mongoose的全局默认连接(也就是需要用mongoose.connect()初始化的连接),而你并没有启动这个全局连接。所以当模型尝试保存数据时,找不到可用的数据库连接,就会一直缓冲直到触发10秒超时。

而GridFS能正常上传文件,是因为你明确给它指定了conn.db这个有效的连接实例。


方案一:统一使用全局默认连接(最简单)

把创建连接的方式改成mongoose.connect(),让GridFS和模型共享同一个全局连接:

1. 修改连接初始化代码

// 替换原来的createConnection,改用全局连接
const mongoose = require('mongoose');
const Grid = require('gridfs-stream');
let gfs;

mongoose.connect(mongoURI, { useNewUrlParser: true, useUnifiedTopology: true })
  .then(() => {
    console.log('MongoDB 全局连接成功');
    // 用全局连接初始化GridFS
    gfs = Grid(mongoose.connection.db, mongoose.mongo);
    gfs.collection("uploads");
  })
  .catch(err => console.error('连接失败:', err));

2. 简化GridFsStorage配置

既然已经有了全局连接,GridFsStorage可以直接复用它,不用再单独传URL:

const storage = new GridFsStorage({
  db: mongoose.connection.db, // 直接使用全局连接的db实例
  file: (req, file) => {
    return new Promise((resolve, reject) => {
      crypto.randomBytes(16, (err, buf) => {
        if (err) {
          return reject(err);
        }
        const filename = buf.toString("hex") + path.extname(file.originalname);
        const fileInfo = {
          filename: filename,
          bucketName: "uploads",
        };
        resolve(fileInfo);
      });
    });
  },
});

方案二:给模型指定独立连接(适合多连接场景)

如果你确实需要用createConnection创建独立连接,那要把这个连接绑定到模型上,让模型使用同一个连接:

1. 调整模型文件,让它接收连接实例

// mediaInfo模型文件
module.exports = (conn) => {
  const Schema = conn.Schema;
  let mediaInfo = new Schema({
    media_id:{ type: String },
    media_name:{ type:String },
    media_description:{ type:String },
  });
  return conn.model('mediaInfos', mediaInfo);
};

2. 在路由中导入模型并传入连接

const conn = mongoose.createConnection(mongoURI, { useNewUrlParser: true, useUnifiedTopology: true });
let gfs;
conn.once("open", () => {
  console.log('独立连接已打开');
  gfs = Grid(conn.db, mongoose.mongo);
  gfs.collection("uploads");
});

// 导入模型并传入连接
const createMediaInfoModel = require('./path/to/your/mediaInfo-model');
const MediaInfo = createMediaInfoModel(conn);

// 后续的上传路由代码不变

额外优化建议

你的路由里res.redirect('/')写在try/catch外面,会导致即使保存失败也会强制跳转,建议调整成:

app.post('/upload',upload.single('file'),async (req,res)=>{
  const fileName = req.file?.filename || null;
  console.log("Media Name "+req.body.medianame);
  
  const mediaInfo = new MediaInfo({
    media_id:fileName,
    media_name:req.body.medianame,
    media_description:req.body.mediadescription
  });

  try{
    await mediaInfo.save();
    res.redirect('/'); // 保存成功再跳转
  }catch(error){
    console.log(error);
    res.status(500).send('文件信息保存失败,请重试'); // 给用户明确的错误提示
  }
});

内容的提问来源于stack exchange,提问作者Niland

火山引擎 最新活动