Node.js GridFS代码迁移后出现findOne未定义错误求助
问题
我有一个从MongoDB通过GFS获取图片的方法,在主app.js中运行正常,但移到单独文件夹后返回错误:
TypeError: Cannot read properties of undefined (reading 'findOne')
相关代码
图片模型文件(images/mongoose.js)
const mongoose = require('mongoose'); const mongoURI = process.env.MONGOURI; const crypto = require("crypto"); const multer = require("multer"); const {GridFsStorage} = require("multer-gridfs-storage"); const Grid = require("gridfs-stream"); const path = require('path'); const conn = mongoose.createConnection(mongoURI); //Init gfs let gridfsBucket; let gfs = conn.once('open', () => { gridfsBucket = new mongoose.mongo.GridFSBucket(conn.db, { bucketName: 'uploads' }); gfs = Grid(conn.db, mongoose.mongo); gfs.collection('uploads'); return gfs; }) //create Storage engine const storage = new GridFsStorage({ limits: { fileSize: 5 * 1000 * 1000 }, url: mongoURI, file: (req, file) => { return new Promise((resolve, reject) => { crypto.randomBytes(8, (err, buf) => { if (err) { return reject(err); } const filename = buf.toString('hex') + path.extname(file.originalname); const fileInfo = { filename: filename, bucketName: 'uploads' }; resolve(fileInfo); }); }); } }); const upload = multer({ storage }); module.exports = { upload, gridfsBucket, gfs, conn }
获取图片路由
const {gridfsBucket} = require('../models/mongoose'); const gfs = require('../models/mongoose'); exports.getImg = (req, res) => { console.log(`req file name is: ${req.params.filename}`); gfs.files.findOne({filename: req.params.filename}, (err, file) => { //Check if file exist if(!file || file.length === 0) { return res.status(404).json({ err: "No file exist" }); } // Check if image if(file.contentType === "image/jpeg" || file.contentType === "image/png" || file.contentType === "image/jpg" || file.contentType === "image/heic") { //Read output to client const readstream = gridfsBucket.openDownloadStreamByName(file.filename); readstream.pipe(res); } else { res.status(404).json({err: "Not an image"}); } }); };
错误栈
TypeError: Cannot read properties of undefined (reading 'findOne') at exports.getImg (/Users/dordadon/Desktop/Full stack course/NerZikaron/controllers/system.js:136:15) at Layer.handle [as handle_request] (/Users/dordadon/Desktop/Full stack course/NerZikaron/node_modules/express/lib/router/layer.js:95:5) at next (/Users/dordadon/Desktop/Full stack course/NerZikaron/node_modules/express/lib/router/route.js:144:13) at Route.dispatch (/Users/dordadon/Desktop/Full stack course/NerZikaron/node_modules/express/lib/router/route.js:114:3) at Layer.handle [as handle_request] (/Users/dordadon/Desktop/Full stack course/NerZikaron/node_modules/express/lib/router/layer.js:95:5) at /Users/dordadon/Desktop/Full stack course/NerZikaron/node_modules/express/lib/router/index.js:284:15 at param (/Users/dordadon/Desktop/Full stack course/NerZikaron/node_modules/express/lib/router/index.js:365:14) at param (/Users/dordadon/Desktop/Full stack course/NerZikaron/node_modules/express/lib/router/index.js:376:14) at Function.process_params (/Users/dordadon/Desktop/Full stack course/NerZikaron/node_modules/express/lib/router/index.js:421:3) at next (/Users/dordadon/Desktop/Full stack course/NerZikaron/node_modules/express/lib/router/index.js:280:10)
解决方案
问题根源
- 异步初始化导致变量未赋值:
gfs和gridfsBucket是在数据库连接成功后才赋值的,但模块导出时这两个变量仍为undefined,路由加载时直接使用会报错。 - 路由导入错误:
const gfs = require('../models/mongoose')导入的是整个模块对象,不是模块内的gfs属性,导致gfs.files为undefined。
修改后的代码
1. 修正模型文件(images/mongoose.js)
用Promise封装异步初始化逻辑,确保连接完成后再返回实例:
const mongoose = require('mongoose'); const mongoURI = process.env.MONGOURI; const crypto = require("crypto"); const multer = require("multer"); const {GridFsStorage} = require("multer-gridfs-storage"); const Grid = require("gridfs-stream"); const path = require('path'); const conn = mongoose.createConnection(mongoURI); let gridfsBucket; let gfs; // 用Promise封装GFS初始化过程 const initGfs = new Promise((resolve) => { conn.once('open', () => { gridfsBucket = new mongoose.mongo.GridFSBucket(conn.db, { bucketName: 'uploads' }); gfs = Grid(conn.db, mongoose.mongo); gfs.collection('uploads'); resolve({ gfs, gridfsBucket }); }); }); const storage = new GridFsStorage({ limits: { fileSize: 5 * 1000 * 1000 }, url: mongoURI, file: (req, file) => { return new Promise((resolve, reject) => { crypto.randomBytes(8, (err, buf) => { if (err) { return reject(err); } const filename = buf.toString('hex') + path.extname(file.originalname); const fileInfo = { filename: filename, bucketName: 'uploads' }; resolve(fileInfo); }); }); } }); const upload = multer({ storage }); module.exports = { upload, initGfs, conn }
2. 修正路由文件
通过async/await等待GFS初始化完成,并修正导入方式:
const { initGfs } = require('../models/mongoose'); exports.getImg = async (req, res) => { try { // 等待GFS初始化完成 const { gfs, gridfsBucket } = await initGfs; console.log(`req file name is: ${req.params.filename}`); const file = await gfs.files.findOne({ filename: req.params.filename }); // 检查文件是否存在 if (!file) { return res.status(404).json({ err: "文件不存在" }); } // 检查是否为图片类型 const allowedTypes = ["image/jpeg", "image/png", "image/jpg", "image/heic"]; if (allowedTypes.includes(file.contentType)) { const readstream = gridfsBucket.openDownloadStreamByName(file.filename); readstream.pipe(res); } else { res.status(404).json({ err: "不是图片文件" }); } } catch (err) { console.error(err); res.status(500).json({ err: "服务器内部错误" }); } };
内容的提问来源于stack exchange,提问作者Dor Dadon
相关产品推荐
相关产品推荐

