使用Node,Express和Multer将文件上传到MongoDB?我应该使用什么,Multer或GRIDfs?

时间:2017-01-20 18:41:15

标签: node.js mongodb mongoose gridfs multer

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

这是Heroku还是Mongolab问题,还是只是免费帐户,因为免费帐户。如果上传了一张照片或者打了十几张照片,它们仍然会在一段时间后消失。

你可以帮帮我吗?是否有一个黑客,棘手的代码或我错误的Multer或我的数据库?我已经在网络和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);

Multer配置

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;

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

2 个答案:

答案 0 :(得分:0)

我不知道这是否有用。但是根据我的理解,multer是用来从用户那里获取数据的东西(比如上传的图像)。它不会持久存储。如果要存储数据(图像等大文件),则应使用gridfs-stream

一旦数据从用户进入,您应该为GridF创建一个读取流。

答案 1 :(得分:0)

如果要将图像保存到数据库,则不应该具有“ 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的模型,并对此进行了建模。我们不需要用猫鼬来验证它,因为multer已经在处理它。确保从删除配置中删除dest属性。因为如果您不删除,multer会将文件保存到文件夹,因此我们的async (req,res){}函数将无法访问该文件,因此我们无法将其保存到数据库。

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

然后在此文件中调用上载模型。

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