我是 Node.js 的新手。谁能给我一个例子,说明如何使用 GridFS 存储和检索二进制数据,例如图像,使用 Node.js 和 Mongoose?我需要直接访问 GridFS 吗?
4 回答
我对这里评分最高的答案不满意,所以我提供了一个新答案:我最终使用了 可以通过 npm 安装的节点模块“gridfs-stream” (那里有很棒的文档!)。有了它,再加上猫鼬,它可能看起来像这样:
var fs = require('fs');
var mongoose = require("mongoose");
var Grid = require('gridfs-stream');
var GridFS = Grid(mongoose.connection.db, mongoose.mongo);
function putFile(path, name, callback) {
var writestream = GridFS.createWriteStream({
filename: name
});
writestream.on('close', function (file) {
callback(null, file);
});
fs.createReadStream(path).pipe(writestream);
}
请注意,路径是本地系统上文件的路径。
至于我的文件读取功能,就我而言,我只需要将文件流式传输到浏览器(使用 express):
try {
var readstream = GridFS.createReadStream({_id: id});
readstream.pipe(res);
} catch (err) {
log.error(err);
return next(errors.create(404, "File not found."));
}
到目前为止的答案都很好,但是,我相信在这里记录如何使用官方的mongodb nodejs 驱动程序而不是依赖于诸如“gridfs-stream”之类的进一步抽象将是有益的。
之前的一个答案确实使用了官方的 mongodb 驱动程序,但是他们使用了 Gridstore API;此后已被弃用,请参见此处。我的示例将使用新的GridFSBucket API。
这个问题非常广泛,因此我的答案将是整个 nodejs 程序。这将包括设置 express 服务器、mongodb 驱动程序、定义路由以及处理 GET 和 POST 路由。
使用的 Npm 包
- express(nodejs Web 应用程序框架,用于简化此代码段)
- multer(用于处理多部分/表单数据请求)
- mongodb(官方 mongodb nodejs 驱动)
GET photo 路由以 Mongo ObjectID 作为参数来检索图像。
我配置 multer 将上传的文件保存在内存中。这意味着照片文件不会随时写入文件系统,而是直接从内存流式传输到 GridFS。
/**
* NPM Module dependencies.
*/
const express = require('express');
const photoRoute = express.Router();
const multer = require('multer');
var storage = multer.memoryStorage()
var upload = multer({ storage: storage, limits: { fields: 1, fileSize: 6000000, files: 1, parts: 2 }});
const mongodb = require('mongodb');
const MongoClient = require('mongodb').MongoClient;
const ObjectID = require('mongodb').ObjectID;
let db;
/**
* NodeJS Module dependencies.
*/
const { Readable } = require('stream');
/**
* Create Express server && Routes configuration.
*/
const app = express();
app.use('/photos', photoRoute);
/**
* Connect Mongo Driver to MongoDB.
*/
MongoClient.connect('mongodb://localhost/photoDB', (err, database) => {
if (err) {
console.log('MongoDB Connection Error. Please make sure that MongoDB is running.');
process.exit(1);
}
db = database;
});
/**
* GET photo by ID Route
*/
photoRoute.get('/:photoID', (req, res) => {
try {
var photoID = new ObjectID(req.params.photoID);
} catch(err) {
return res.status(400).json({ message: "Invalid PhotoID in URL parameter. Must be a single String of 12 bytes or a string of 24 hex characters" });
}
let bucket = new mongodb.GridFSBucket(db, {
bucketName: 'photos'
});
let downloadStream = bucket.openDownloadStream(photoID);
downloadStream.on('data', (chunk) => {
res.write(chunk);
});
downloadStream.on('error', () => {
res.sendStatus(404);
});
downloadStream.on('end', () => {
res.end();
});
});
/**
* POST photo Route
*/
photoRoute.post('/', (req, res) => {
upload.single('photo')(req, res, (err) => {
if (err) {
return res.status(400).json({ message: "Upload Request Validation Failed" });
} else if(!req.body.name) {
return res.status(400).json({ message: "No photo name in request body" });
}
let photoName = req.body.name;
// Covert buffer to Readable Stream
const readablePhotoStream = new Readable();
readablePhotoStream.push(req.file.buffer);
readablePhotoStream.push(null);
let bucket = new mongodb.GridFSBucket(db, {
bucketName: 'photos'
});
let uploadStream = bucket.openUploadStream(photoName);
let id = uploadStream.id;
readablePhotoStream.pipe(uploadStream);
uploadStream.on('error', () => {
return res.status(500).json({ message: "Error uploading file" });
});
uploadStream.on('finish', () => {
return res.status(201).json({ message: "File uploaded successfully, stored under Mongo ObjectID: " + id });
});
});
});
app.listen(3005, () => {
console.log("App listening on port 3005!");
});
我写了一篇关于这个主题的博客文章;是对我的回答的详细说明。在这里可用
进一步阅读/灵感:
我建议看看这个问题:MongoDB GridFS Saving Files with Node.JS 的问题
从答案中复制的示例(归功于 christkv):
// You can use an object id as well as filename now
var gs = new mongodb.GridStore(this.db, filename, "w", {
"chunk_size": 1024*4,
metadata: {
hashpath:gridfs_name,
hash:hash,
name: name
}
});
gs.open(function(err,store) {
// Write data and automatically close on finished write
gs.writeBuffer(data, true, function(err,chunk) {
// Each file has an md5 in the file structure
cb(err,hash,chunk);
});
});
看起来 writeBuffer 已经被弃用了。
/Users/kmandrup/private/repos/node-mongodb-native/HISTORY:
82 * Fixed dereference method on Db class to correctly dereference Db reference objects.
83 * Moved connect object onto Db class(Db.connect) as well as keeping backward compatibility.
84: * Removed writeBuffer method from gridstore, write handles switching automatically now.
85 * Changed readBuffer to read on Gridstore, Gridstore now only supports Binary Buffers no Strings anymore.