Cómo usar GridFS para almacenar imágenes usando Node.js y Mongoose

Soy nuevo en Node.js. ¿Puede alguien proporcionarme un ejemplo de cómo usar GridFS para almacenar y recuperar datos binarios, como imágenes, usando Node.js y Mongoose? ¿Necesito acceder directamente a GridFS?

No estaba satisfecho con la respuesta con la calificación más alta aquí, así que estoy proporcionando una nueva: terminé usando el módulo de nodo ‘gridfs-stream’ (¡excelente documentación allí!) Que se puede instalar a través de npm. Con él, y en combinación con la mongoose, podría verse así:

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); } 

Tenga en cuenta que la ruta es la ruta del archivo en el sistema local.

En cuanto a mi función de lectura del archivo, para mi caso solo necesito transmitir el archivo al navegador (usando Express):

 try { var readstream = GridFS.createReadStream({_id: id}); readstream.pipe(res); } catch (err) { log.error(err); return next(errors.create(404, "File not found.")); } 

Sugiero echar un vistazo a esta pregunta: Problema con MongoDB GridFS Guardar archivos con Node.JS

Ejemplo copiado de la respuesta (el crédito va a 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); }); }); 

Las respuestas son buenas hasta ahora, sin embargo, creo que sería beneficioso documentar aquí cómo hacerlo utilizando el controlador oficial mongodb nodejs en lugar de depender de otras abstracciones como “gridfs-stream”.

Una respuesta anterior ha utilizado el controlador oficial mongodb, sin embargo, utilizan la API de Gridstore; que desde entonces ha quedado en desuso, ver aquí . Mi ejemplo será usar la nueva API GridFSBucket .

La pregunta es bastante amplia ya que mi respuesta será un progtwig completo de nodejs. Esto incluirá la configuración del servidor Express, el controlador mongodb, la definición de las rutas y el manejo de las rutas GET y POST.

Paquetes Npm Usados

  • Express (framework de aplicaciones web nodejs para simplificar este fragmento)
  • multer (para el manejo de solicitudes multipart / form-data)
  • mongodb (controlador oficial mongodb nodejs)

La ruta de fotos GET toma un Mongo ObjectID como parámetro para recuperar la imagen.

Configuré multer para mantener el archivo cargado en la memoria. Esto significa que el archivo de fotos no se escribirá en el sistema de archivos en ningún momento, y en su lugar se transmitirá directamente desde la memoria a 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!"); }); 

Escribí una entrada de blog sobre este tema; Es una elaboración de mi respuesta. Disponible aqui

Lectura / inspiración adicional:

  • NodeJs Streams: todo lo que necesitas saber
  • Multer NPM docs
  • Controlador Nodejs MongoDB

Parece que el writeBuffer ha sido desaprobado.

 /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.