如何使用 GridFS 使用 Node.js 和 Mongoose 存储图像
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/8135718/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to use GridFS to store images using Node.js and Mongoose
提问by Dar Hamid
I am new to Node.js. Can anyone provide me an example of how to use GridFS for storing and retrieving binary data, such as images, using Node.js and Mongoose? Do I need to directly access GridFS?
我是 Node.js 的新手。谁能为我提供一个示例,说明如何使用 GridFS 存储和检索二进制数据,例如使用 Node.js 和 Mongoose 的图像?我是否需要直接访问 GridFS?
回答by Mitja
I was not satisfied with the highest rated answer here and so I'm providing a new one: I ended up using the node module 'gridfs-stream'(great documentation there!) which can be installed via npm. With it, and in combination with mongoose, it could look like this:
我对这里评分最高的答案不满意,所以我提供了一个新答案:我最终使用了节点模块 “gridfs-stream”(那里有很棒的文档!),它可以通过 npm 安装。有了它,再加上猫鼬,它可能看起来像这样:
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);
}
Note that path is the path of the file on the local system.
请注意,path 是文件在本地系统上的路径。
As for my read function of the file, for my case I just need to stream the file to the browser (using express):
至于我的文件读取功能,就我而言,我只需要将文件流式传输到浏览器(使用 express):
try {
var readstream = GridFS.createReadStream({_id: id});
readstream.pipe(res);
} catch (err) {
log.error(err);
return next(errors.create(404, "File not found."));
}
回答by Riky_Tree
Answers so far are good, however, I believe it would be beneficial to document here how to do this using the official mongodb nodejs driverinstead of relying on further abstractions such as "gridfs-stream".
到目前为止的答案都很好,但是,我相信在此处记录如何使用官方mongodb nodejs 驱动程序而不是依赖诸如“gridfs-stream”之类的进一步抽象来执行此操作将是有益的。
One previous answer has indeed utilized the official mongodb driver, however they use the Gridstore API; which has since been deprecated, see here. My example will be using the new GridFSBucket API.
之前的一个答案确实使用了官方的 mongodb 驱动程序,但是他们使用了 Gridstore API;此后已弃用,请参阅此处。我的示例将使用新的GridFSBucket API。
The question is quite broad as such my answer will be an entire nodejs program. This will include setting up the express server, mongodb driver, defining the routes and handling the GET and POST routes.
这个问题非常广泛,因此我的答案将是一个完整的 nodejs 程序。这将包括设置快速服务器、mongodb 驱动程序、定义路由以及处理 GET 和 POST 路由。
Npm Packages Used
使用的 Npm 包
- express (nodejs web application framework to simplify this snippet)
- multer (for handling multipart/form-data requests)
- mongodb (official mongodb nodejs driver)
- express(用于简化此代码段的 nodejs Web 应用程序框架)
- multer(用于处理多部分/表单数据请求)
- mongodb(官方 mongodb nodejs 驱动程序)
The GET photo route takes a Mongo ObjectID as a parameter to retrieve the image.
GET photo 路由以 Mongo ObjectID 作为参数来检索图像。
I configure multer to keep the uploaded file in memory. This means the photo file will not be written to the file system at anytime, and instead be streamed straight from memory into GridFS.
我配置 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!");
});
I wrote a blog post on this subject; is is an elaboration of my answer. Available here
我写了一篇关于这个主题的博客文章;是对我的回答的详细说明。在这里可用
Further Reading/Inspiration:
进一步阅读/灵感:
回答by blockchaindev
I suggest taking a look at this question: Problem with MongoDB GridFS Saving Files with Node.JS
我建议看看这个问题:Problem with MongoDB GridFS Saving Files with Node.JS
Copied example from the answer (credit goes to christkv):
从答案中复制的示例(归功于 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);
});
});
回答by Kristian
It looks like the writeBuffer has since been deprecated.
看起来 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.

