Comment utiliser GridFS pour stocker des images en utilisant Node.js et Mongoose

je suis nouveau sur le Nœud.js. Est-ce que quelqu'un peut me fournir un exemple d'utilisation de GridFS pour stocker et récupérer des données binaires, telles que des images, en utilisant le noeud.js et Mongoose? Dois-je accéder directement à GridFS?

15
demandé sur EhevuTov 2011-11-15 15:34:17

4 réponses

Je n'étais pas satisfait de la réponse la mieux notée ici et donc je vous en donne une nouvelle: J'ai fini par utiliser le module de noeud 'gridfs-stream' (très bonne documentation!) qui peut être installé via npm. Avec elle, et en combinaison avec la mangouste, il pourrait ressembler à ceci:

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

Notez que le chemin est le chemin d'accès du fichier sur le système local.

en ce qui concerne ma fonction de lecture du fichier, pour mon cas j'ai juste besoin de streamer le fichier vers le navigateur (en utilisant express):

try {
    var readstream = GridFS.createReadStream({_id: id});
    readstream.pipe(res);
} catch (err) {
    log.error(err);
    return next(errors.create(404, "File not found."));
}
20
répondu Mitja 2014-04-09 16:34:37

je suggère de jeter un oeil à cette question: problème avec MongoDB GridFS sauvegarde des fichiers avec noeud.JS

exemple copié de la réponse (le crédit va à 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);
  });
});
8
répondu blockchaindev 2017-05-23 12:24:40

les réponses jusqu'à présent sont bonnes, cependant, je crois qu'il serait bénéfique de documenter ici comment faire cela en utilisant le mongodb nodejs pilote au lieu de s'appuyer sur d'autres abstractions comme "gridfs-stream".

une réponse précédente a en effet utilisé le pilote mongodb officiel, cependant ils utilisent L'API Gridstore; qui a depuis été déprécié, voir ici. Mon exemple sera d'utiliser le nouveau GridFSBucket API.

la question est assez large en tant que telle ma réponse sera un programme nodejs entier. Il s'agira notamment de configurer le serveur express, le pilote mongodb, de définir les routes et de gérer les routes GET et POST.

Paquets Npm Utilisés

  • express (nodejs cadre d'application de web pour simplifier cet extrait de code)
  • multer (pour la manipulation multipart/form-data demandes)
  • mongodb (officiel mongodb nodejs le pilote)

la route GET photo prend un objet Mongo comme paramètre pour récupérer l'image.

j'ai configuré multer pour garder le fichier téléchargé en mémoire. Cela signifie que le fichier photo ne sera pas écrit dans le système de fichiers à n'importe quel moment, et sera plutôt streamé directement de la mémoire dans 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!");
});

j'ai écrit un billet de blog sur ce sujet; est est une élaboration de ma réponse. Disponible ici

Autres Lectures / Inspiration:

6
répondu Riky_Tree 2017-11-16 19:57:46

on dirait que le correcteur d'écriture a été déprécié depuis.

/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.
3
répondu Kristian 2012-04-10 16:07:24