Vraag Hoe GridFS te gebruiken om afbeeldingen op te slaan met Node.js en Mongoose


Ik ben nieuw bij Node.js. Kan iemand mij een voorbeeld geven van het gebruik van GridFS voor het opslaan en ophalen van binaire gegevens, zoals afbeeldingen, met Node.js en Mongoose? Heb ik rechtstreeks toegang tot GridFS nodig?


15
2017-11-15 11:34


oorsprong


antwoorden:


Ik was niet tevreden met het antwoord met de hoogste beoordeling hier en dus geef ik een nieuw antwoord: Ik heb uiteindelijk de knooppuntmodule gebruikt 'Gridfs-stream' (geweldige documentatie daar!) die via npm kan worden geïnstalleerd. Hiermee en in combinatie met mongoose kan het er zo uitzien:

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

Merk op dat pad het pad is van het bestand op het lokale systeem.

Wat betreft mijn leesfunctie van het bestand, in mijn geval moet ik het bestand gewoon naar de browser streamen (via 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
2018-04-09 16:34



Ik stel voor om deze vraag eens te bekijken: Probleem met MongoDB GridFS Bestanden opslaan met Node.JS

Voorbeeld uit het antwoord gekopieerd (credit gaat naar 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
2017-11-15 12:29



Antwoorden tot nu toe zijn goed, maar ik denk dat het nuttig zou zijn om hier te documenteren hoe dit te doen met behulp van de officiële mongodb nodejs-stuurprogramma in plaats van te vertrouwen op verdere abstracties zoals "gridfs-stream".

Eén eerder antwoord heeft inderdaad de officiële mongodb-driver gebruikt, maar ze gebruiken de Gridstore-API; die sindsdien is verouderd, zie hier. Mijn voorbeeld zal het nieuwe gebruiken GridFSBucket API.

De vraag is vrij breed, daarom zal mijn antwoord een heel nodejs-programma zijn. Dit omvat het instellen van de express-server, mongodb-stuurprogramma, het definiëren van de routes en het afhandelen van de GET- en POST-routes.

Npm-pakketten gebruikt

  • express (nodejs web application framework om dit fragment te vereenvoudigen)
  • multer (voor het verwerken van verzoeken om meerdere of form-data)
  • mongodb (officiële mongodb knooppunt driver)

De GET-fotoroute neemt een Mongo-object-ID als een parameter om de afbeelding op te halen.

Ik configureer multer om het geüploade bestand in het geheugen te houden. Dit betekent dat het fotobestand op geen enkel moment naar het bestandssysteem wordt geschreven en in plaats daarvan rechtstreeks vanuit het geheugen naar GridFS wordt gestreamd.


/**
 * 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!");
});

Ik schreef een blogpost over dit onderwerp; is is een uitwerking van mijn antwoord. Beschikbaar hier

Verder lezen / inspiratie:


6
2017-11-08 22:27



Het lijkt erop dat de writeBuffer sindsdien is verouderd.

/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
2018-04-09 20:53