Как отображать изображения из mongodb gridfs - PullRequest
0 голосов
/ 29 июня 2019

Я пытаюсь создать веб-приложение, в которое пользователи могут загружать некоторые изображения, и для выполнения этой задачи я использую gridfs.

Я решил, как правильно их сохранить, но проблемы начинаютсякогда мне нужно отобразить их.

Для сохранения изображений я использую этот код

Сохранить изображения

const mongoURI = "mongodb://localhost:27017/upload_images";
mongoose.set('useNewUrlParser', true);
mongoose.set('useFindAndModify', false);
mongoose.connect(mongoURI);
const conn = mongoose.connection;

// Init gfs
let gfs;

conn.once('open', () => {
    // Init stream
    gfs = Grid(conn.db, mongoose.mongo);
    gfs.collection('uploaded_images'); //collection name
});

// Create storage engine
const storage = new GridFsStorage({
  url: mongoURI,
  file: (req, file) => {
    return new Promise((resolve, reject) => {
      crypto.randomBytes(16, (err, buf) => {
        if (err) {
          return reject(err);
        }
        const filename = buf.toString('hex') + path.extname(file.originalname);
        const fileInfo = {
          filename: filename,
          bucketName: 'uploaded_images' //collection name
        };
        resolve(fileInfo);
      });
    });
  }
});
const upload = multer({ storage });

router.post('/posts', upload.single('file'), (req, res) => {

    file = req.file;

    if(file){
        req.body.post.image_file = file.id;
    }

    Post.create(req.body.post, (err, post) => {
        if(err){
            res.redirect('/posts');
        } else {
            res.redirect('/posts');
        }
    });
});

и изображения сохраняются правильноТеперь мне нужно отобразить их.

У меня есть mongoose схема поста, где я сохраняю некоторые данные и ссылку на загруженное изображение (ObjectId)

Пост-схема

const mongoose = require('mongoose');

var PostSchema = new mongoose.Schema({
    image_link: String,
    image_file: [{
            type: mongoose.Schema.Types.ObjectId,
            ref: 'GFS'  
        }],
    brand: String,
    model: String,
    moto_type: String,
    date : {type : Date, default : Date.now}, 
    categories : [{
        title: String,
        content: String,
    }],
    comments: [{
            type: mongoose.Schema.Types.ObjectId,
            ref: 'Comment'  
        }],
    views: {type: String, default: '0'}
});


module.exports = mongoose.model('Post', PostSchema, 'posts');

И схема gridfs для использования ссылки внутри схемы сообщения

Схема GridFs

const mongoose = require('mongoose');

var gridFsSchema = new mongoose.Schema({});

module.exports = mongoose.model('GFS', gridFsSchema, 'uploaded_images.files');

Мои проблемы начинаются, когдая пытаюсь отобразить сообщение


router.get('/posts/:post_id', (req, res) => {

    post_id = req.params.post_id;

    Post.findById(post_id)
    .populate('comments')
    .populate('image_file')
    .exec((err, post) => {
        if(err){
            console.log(err)
            res.redirect('/posts');
        } else {
            res.render('posts/show', {post: post})
        }
    });
});

Первая проблема заключается в том, что метод .populate('image_file') выдает эту ошибку

{ MissingSchemaError: Schema hasn't been registered for model "GFS".
Use mongoose.model(name, schema)
    at new MissingSchemaError (/home/pero/motoWebApp/node_modules/mongoose/lib/error/missingSchema.js:22:11)
    at NativeConnection.Connection.model (/home/pero/motoWebApp/node_modules/mongoose/lib/connection.js:925:11)
    at getModelsMapForPopulate (/home/pero/motoWebApp/node_modules/mongoose/lib/model.js:4434:59)
    at populate (/home/pero/motoWebApp/node_modules/mongoose/lib/model.js:3979:21)
    at _populate (/home/pero/motoWebApp/node_modules/mongoose/lib/model.js:3949:5)
    at utils.promiseOrCallback.cb (/home/pero/motoWebApp/node_modules/mongoose/lib/model.js:3924:5)
    at Object.promiseOrCallback (/home/pero/motoWebApp/node_modules/mongoose/lib/utils.js:249:12)
    at Function.Model.populate (/home/pero/motoWebApp/node_modules/mongoose/lib/model.js:3923:16)
    at model.Query.Query._completeOne (/home/pero/motoWebApp/node_modules/mongoose/lib/query.js:2018:9)
    at Immediate.Query.base.findOne.call (/home/pero/motoWebApp/node_modules/mongoose/lib/query.js:2057:10)
    at Immediate.<anonymous> (/home/pero/motoWebApp/node_modules/mquery/lib/utils.js:116:16)
    at runCallback (timers.js:705:18)
    at tryOnImmediate (timers.js:676:5)
    at processImmediate (timers.js:658:5)
  message:
   'Schema hasn\'t been registered for model "GFS".\nUse mongoose.model(name, schema)',
  name: 'MissingSchemaError' }

Во-вторых, я не понимаю, как отобразитьизображение, когда я делаю запрос на получение /posts/:post_id

1 Ответ

0 голосов
/ 30 июня 2019

Я решил это:

Для правильного отображения изображений с помощью gridfs Вам необходимо выполнить следующие шаги:

1)

Когда вы загружаете файл, сохраняйте идентификатор в качестве схемы в вашей схеме, чтобы после этого можно было заполнить его .populate method. Вы можете сохранить его как ссылку, вставив эти строки в схему

image_file: {
        type: mongoose.Schema.Types.ObjectId, 
        ref: 'GridFs' 
    },

2)

создать модель grifs для использования в качестве ссылки для загруженных файлов

const mongoose = require('mongoose');

var GridfsSchema = new mongoose.Schema({
    filename: String
}, {strict: false});

module.exports = mongoose.model('GridFs', GridfsSchema, 'uploaded_images.files' );

Ошибка, которая у меня возникла в вопросе, была выброшена, потому что я определил модель во внешнем файле и никогда не импортировал ее.

3)

определить маршрут для рендеринга файлов:


const express                   = require('express'),
      router                    = express.Router(),
      mongoose                  = require('mongoose'),
      path                      = require('path'),
      multer                    = require('multer'),
      crypto                    = require('crypto'),
      Grid                      = require('gridfs-stream'),
      GridFsStorage             = require('multer-gridfs-storage'),

      Post                      = require('../models/post');

const conn = mongoose.connection;
const mongoURI = "mongodb://localhost:27017/moto_website";

// Init gfs
let gfs;

conn.once('open', () => {
    // Init stream
    gfs = Grid(conn.db, mongoose.mongo);
    gfs.collection('uploaded_images'); //collection name
});

router.get('/image/:filename', (req, res) => {
    gfs.files.findOne({filename: req.params.filename}, (err, file) => {
        if(!file || file.length === 0){
            return res.status(404).json({err: 'No File Exists'});
        } else {
            // Check if is image
            if(file.contentType === "image/jpeg" || file.contentType === "image/png"){
                // Read output to broswer
                const readstream = gfs.createReadStream(file.filename);
                readstream.pipe(res);
            } else {
                res.status(404).json({err: 'Not and image'});
            }
        }
    });
});

теперь каждый раз, когда вы идете по пути /images/:image_name, отображается изображение с именем :image_name

4)

установлен как src атрибут ваших <img> тегов пути /images/<your_filename_in_gridfs.files>

Источники

У меня были некоторые ошибки, прежде чем найти решение

1) Я мог бы получить заполненные объекты, но не их атрибуты, которые дали мне неопределенные значения. Это потому, что в схеме gridfs у меня был пустой объект, поэтому я не мог ничего получить. Определив в Schema атрибут filename: String, я решил его (только для атрибута имени файла, другие атрибуты будут возвращаться неопределенными. Если вы хотите прочитать их тоже, вы должны написать их внутри gridfs Schema). См. Этот ответ

2) Я не знал, как связать файлы gridfs с относительной ссылкой См. Этот ответ

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...