【问题标题】:Using Node, Express and Multer for Upload a file to MongoDB? What should I use, Multer or GRIDfs?使用 Node、Express 和 Multer 将文件上传到 MongoDB?我应该使用什么,Multer 或 GRIDfs?
【发布时间】:2017-06-05 20:08:20
【问题描述】:

您好,我正在使用 MongoLab 和 Multer 在 heroku 上运行最终项目来上传照片似乎工作正常,但几个小时或更短时间后,照片从页面上消失,但留下了 img 占位符和另一个字段,如名称或日期区域它在哪里。

这是 Heroku 或 Mongolab 的问题,还是只是免费帐户是因为免费帐户。同样,上传一张照片或十几张照片也没关系,它们仍然会在一段时间后消失。

你能帮帮我吗? Multer 或我的数据库是否存在 hack、棘手的代码行或我做错了什么?我对网络和 Stack-Overflow 进行了深入研究,我发现了一个叫做 GRIDfs 的东西,但我不知道这是否可行。你能告诉我我是否正确吗?

这是我的 Multer 代码:

var express        = require("express"),
    body_parser    = require("body-parser"),
    multer         = require("multer"),
    mongoose       = require("mongoose");

    var app = express();

    //connect my local database to MongoLab database   

    var url = process.env.DATABASE || "mongodb://localhost/black_hat";

    mongoose.connect(url);

多重配置

var storage = multer.diskStorage({
destination: function(req, file, callback){
    callback(null, "./public/uploads");
},
filename: function(req, file, callback){
    callback(null, Date.now() + file.originalname);
}
  });

var upload = multer({storage : storage}).single("image");

我的 POST 路线

    app.post("/fotos_videos", isLoggedIn, function(req, res) {
    upload(req, res, function(err) {
        if(err){
            return res.end("Error uploading file");
        }
        // get data from form
        var newName = req.body.name,
            newCover = "/uploads/" + req.file.filename;
        // Packing into an object
        var newCollage = {
            name : newName,
            cover: newCover
        };
        //create new album
        Collage.create(newCollage, function(err, collage) {
            if(err){
                console.log(err);
            } else {
                // console.log(collage);
                res.redirect("/fotos_videos");
            }
        });
    });
});

我上传图片的表单

    <div style="width=30%; margin: 30px auto" >
        
        <form action="/fotos_videos" method="POST" enctype="multipart/form-data">
            <div class="form-group">
                <label>Album Name</label>
                <input type="text" name="name" placeholder="Album Name" class="form-control">
            </div>
            <div class="form-group">
                <label>Choose Album Cover</label>
                <input type="file" name="image" placeholder="image url" class="form-control" required>
            </div>
            
            <div class="form-group">
                <button class="btn btn-lg btn-primary btn-block">Upload</button>
            </div>
        </form>
        
        <a href="/fotos_videos">Back</a>
        
    </div>

最后是我的拼贴模型

var mongoose = require("mongoose");

// Schema 
var collageSchema = new mongoose.Schema({
    name : String,
    cover : String,
    photos: [{
        type: mongoose.Schema.Types.ObjectId,
        ref: "Photo"
    }] 
});

var Collage = mongoose.model("Collage", collageSchema);

module.exports = Collage;

我们将不胜感激任何形式的帮助。

【问题讨论】:

    标签: node.js mongodb mongoose gridfs multer


    【解决方案1】:

    我不知道这是否会有所帮助。但据我了解,multer 是用来从用户那里获取数据的东西(比如上传的图片)。它不进行持久存储。如果你想存储数据(像图片这样的大文件)你应该使用gridfs-stream

    一旦数据来自用户,您应该创建一个到 GridFs 的读取流。

    【讨论】:

    • 感谢@jackblack 的评论,我确实想要持久存储。我找到了gridfs-stream,但你能给我举个例子吗?你已经明白我的问题了!!我想要实现的是用户上传照片和关于该照片的描述,然后在网络浏览器中向我显示该信息(图片和描述),然后用户可能想要编辑或删除该照片。就像 CRUD 应用程序一样,我已经使用 mongoose 和 Multer 实现了该功能,但就像您看到的那样,这不适用于使数据持久化。欢迎任何帮助
    • @CarlosMoreno 您可以使用 gridfs-stream 并且可以像使用 multer 上传普通文件一样上传和下载图像。哪个更好我仍然很困惑我也找到了答案:)
    【解决方案2】:

    如果你想将图像保存到数据库你不应该有“dest”属性。 multer 的实现也是错误的,可能是因为这是一个老问题,以前的 api 就是这样。你应该怎么做。

    配置你的 multer:

    const multer = require("multer");
    const upload = multer({
      limits: { fileSize: 5000000 },
      fileFilter(req, file, cb) {
        if (!file.originalname.match(/\.(jpg|jpeg|png)$/)) { //allowed file extensions
          return cb(new Error("please upload png,jpeg or jpg"));
        }
        cb(undefined, true);
      }
    });
    

    然后创建一个端点。你已经有了这个

    app.post("/fotos_videos", isLoggedIn, function(req, res) {
       upload(req, res, function(err) { 
    

    这个实施错误。 upload 是一个中间件,如果您想添加身份验证,则只有经过身份验证的用户才能访问此端点。所以我们需要调整这个端点。

    您还需要为上传定义一个架构,以便将它们保存到数据库中。假设您创建了一个名为 uploads 的模型,并将其命名为 this。我们不需要通过 mongoose 验证它,因为 multer 已经处理了它。确保你从 multer 配置中删除 dest 属性。因为如果您不删除,multer 会将文件保存到文件夹中,因此我们的async (req,res){} 函数将无法访问该文件,因此我们无法将其保存到数据库中。

    uploads:{type:Buffer} //将其包含在您的上传架构中

    然后在这个文件中调用 Uploads 模型。

    router.post(
      "/fotos_videos/me/uploads", isLoggedIn,
      upload.single("uploads"),  //uploads is just a random name when u upload from postman, form form-data,put "uploads" in key field
      async (req, res) => {
        req.upload.uploads = req.file.buffer;//i explain down below
        await req.upload.save();
        res.send();
      },
      (err, req, res) => {
        res.status(400).send("error happned");
      }
    );
    

    我们不会将图片存储在文件系统中。原因几乎是所有部署平台,都要求我们将代码推送到他们服务器上的存储库。因此,每次部署时文件系统都会被擦除,这意味着我们在部署时会丢失数据。因此,我们将在用户模型中添加一个字段,以将二进制数据的图像存储在数据库中,而不是将图像存储在文件系统中。

    现在是时候从数据库中获取我们的图像了。为此,您需要有一条新路线

    router.get("/fotos_videos/:id/uploads", async (req, res) => {
      try {
        const upload = await Uploads.findById(req.params.id);
        if (!upload || !upload.uploads) {
          throw new Error("no image found");
        }
        res.set("Content-Type", "image/png");
        res.send(upload.uploads);
      } catch (e) {
        res.status(400).send(e.message);
      }
    });
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-03-01
      • 2017-01-04
      • 2017-11-12
      • 2016-10-22
      • 2018-11-23
      • 2019-02-21
      • 2015-10-21
      • 2018-09-26
      相关资源
      最近更新 更多