Frage Wie verwende ich GridFS zum Speichern von Bildern mit Node.js und Mongoose?


Ich bin neu bei Node.js. Kann mir jemand ein Beispiel für die Verwendung von GridFS zum Speichern und Abrufen von Binärdaten wie Bildern mithilfe von Node.js und Mongoose geben? Muss ich direkt auf GridFS zugreifen?


15
2017-11-15 11:34


Ursprung


Antworten:


Ich war mit der bestbewerteten Antwort hier nicht zufrieden und deshalb biete ich eine neue an: Ich benutzte das Knotenmodul 'gridfs-stream' (tolle Dokumentation dort!) die über npm installiert werden kann. Damit und in Verbindung mit Mungo könnte es so aussehen:

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

Beachten Sie, dass Pfad der Pfad der Datei auf dem lokalen System ist.

Wie für meine Lesefunktion der Datei, für meinen Fall muss ich nur die Datei zum Browser streamen (mit 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



Ich schlage vor, einen Blick auf diese Frage zu werfen: Problem mit MongoDB GridFS Speichern von Dateien mit Node.JS

Kopiertes Beispiel aus der Antwort (Kredit geht an 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



Die bisherigen Antworten sind gut, aber ich glaube, es wäre von Vorteil, hier zu dokumentieren, wie man das mit dem Beamten macht mongodb nodejs Treiber anstatt sich auf weitere Abstraktionen wie "gridfs-stream" zu verlassen.

Eine frühere Antwort hat tatsächlich den offiziellen mongodb-Treiber verwendet, sie verwenden jedoch die Gridstore-API; was seither veraltet ist, siehe Hier. Mein Beispiel wird das neue verwenden GridFSBucket API.

Die Frage ist ziemlich weit, da so meine Antwort ein ganzes nodejs Programm sein wird. Dies umfasst die Einrichtung des Express-Servers, des mongodb-Treibers, die Definition der Routen und die Handhabung der GET- und POST-Routen.

Npm-Pakete verwendet

  • express (nodejs Web Application Framework zur Vereinfachung dieses Snippets)
  • multer (für die Behandlung von Multipart- / Formulardatenanforderungen)
  • mongodb (offizieller mongodb nodejs Treiber)

Die GET-Foto-Route verwendet eine Mongo-Objekt-ID als Parameter, um das Bild abzurufen.

Ich konfiguriere multer, um die hochgeladene Datei im Speicher zu behalten. Dies bedeutet, dass die Fotodatei nicht jederzeit in das Dateisystem geschrieben und stattdessen direkt aus dem Speicher in GridFS gestreamt wird.


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

Ich habe einen Blogbeitrag zu diesem Thema geschrieben; Das ist eine Ausarbeitung meiner Antwort. Verfügbar Hier

Weiterführende Literatur / Inspiration:


6
2017-11-08 22:27



Es sieht so aus, als wäre der WriteBuffer seither veraltet.

/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