Express Multer req.files is undefined - node.js

Whenever I upload an image, req.files returns undefined.
This is my code:
var upload123 = multer({
dest: path.join(__dirname, 'public/upload/temp'),
});
app.post(upload123);
This is the HTML:
<form action="/images" method="POST" enctype="multipart/form-data">
<div class="panel-body form-horizontal">
<div class="form-group col-md-12">
<label for="file" class="col-md-2 control-label">Browse:</label>
<div class="col-md-10">
<input type="file" class="form-control" id="file" name="file">
</div>
</div>
This is the controller I am trying to access req.files in:
create(req, res) {
const saveImage = function() {
const possible = 'abcdefghijklmnopqrstuvwxyz0123456789';
let imgUrl = '';
for(let i = 0; i < 6; i++) {
imgUrl += possible.charAt(Math.floor(Math.random() * possible.length));
}
Models.Image.find({ filename: imgUrl }, (err, images) => {
if (images.length > 0) saveImage();
else {
var tempPath = req.files.file.path,
ext = path.extname(req.files.file.name).toLowerCase(),
targetPath = path.resolve(`./public/upload/${ imgUrl }${ ext }`);
if (ext === '.png' || ext === '.jpg' || ext === '.jpeg' || ext === '.gif') {
fs.rename(tempPath, targetPath, (err) => {
if (err) throw err;
var newImg = new Models.Image({
title: req.body.title,
description: req.body.description,
filename: imgUrl + ext
});
newImg.save((err, image) => {
res.redirect(`/images/${image.uniqueId}`);
});
});
} else {
fs.unlink(tempPath, () => {
if (err) throw err;
res.json(500, {error: 'Only image files are allowed'});
})
}
}
});
}
saveImage();
}
I am using Express version 4.16.3 and Multer 1.3.0.
I check the docs but couldn't figure out how to simply provide a dest option in Multer. Please help, am new to Nodejs

This is example from code that is working properly:
const multer = require('multer');
const storage = multer.memoryStorage();
const fileUpload = multer({storage});
app.use('/*', fileUpload.single('file'));
If you have this in beginning of your application and you put controllers after this middleware, then in req.file you will have file
The best thing is that it is stored directly in memory, not in some file, so you dont have to load it from filesystem. (which is also safer, especially when you deploy your app to some cloud services and containers, which makes it less visible)
If you insist on your "file-on-disk" solution, based on official docs: https://www.npmjs.com/package/multer you should use it as this:
var upload123 = multer({
dest: path.join(__dirname, 'public/upload/temp'),
});
app.post('/endpoint/to/upload/photos', upload123.single('file'), controller.handleImage);

Related

How to decode binary image data retrieved from mongodb in nodejs

I am trying to upload and retrieve image to and from mongodb through nodejs and mutter. But i am stuck some where, i hope i am succeeded in uploading image as binary data. but not displaying image in my .ejs file.
Routes file
const express=require('express');
const adminRouter=express.Router();
const Bookdata=require('../model/Bookdata')
const multer = require('multer');
const path = require('path');
var fs = require('fs');
const {
GridFsStorage
} = require("multer-gridfs-storage");
require("dotenv")
.config();
// set up multer for storing uploaded files
const storage=multer.diskStorage({
//destination for files
destination:function(request,file,callback){
callback(null,'../LibraryApps/public/uploads/images');
},
//add back the extensions
filename:function(request,file, callback){
callback(null,file.fieldname+Date.now()+path.extname(file.originalname));
}
})
//upload parameters for mutter
const upload = multer({
storage: storage,
limits:{
fileSize: 1000000
},
fileFilter:function(req,file,callback){
checkFileType(file, callback);
}
});
//Check file type
function checkFileType(file, callback){
// allowed extension
const filetypes = /jpeg|jpg|png|gif/;
//check extension
const extname=filetypes.test(path.extname(file.originalname).toLowerCase());
//check mime
const mimetype=filetypes.test(file.mimetype);
if(mimetype&&extname){
return callback(null, true);
}else{
callback('Error: Images only');
}
}
var imgModel = require('../model/Bookdata');
function router(nav){
adminRouter.get('/',function(req,res){
imgModel.find({}, (err, items) => {
if (err) {
console.log(err);
res.status(500).send('An error occurred', err);
}
else {
//res.render('imagesPage', { items: items });
res.render('addBook',{
nav,
title:'Library'
})
}
});
})
adminRouter.post('/add',upload.single(`image`), function(req,res){
// res.send("Hey I am Added");
console.log(req.file);
var item={
title: req.body.title,
author: req.body.author,
genre: req.body.genre,
//image: req.file.image,
image: {
data: fs.readFileSync(path.join('../LibraryApps/public/uploads/images/' + req.file.filename)),
contentType: 'image/png'
}
}
imgModel.create(item, (err, item) => {
if (err) {
console.log(err);
}
else {
var book=Bookdata(item);
book.save();
res.redirect('/books');
}
});
});
return adminRouter;
}
module.exports=router;
my model file
//Accessing Mongose package
const mongoose=require('mongoose');
//Database connection
// mongoose.connect('mongodb://localhost:27017/library');
mongoose.connect('mongodb....');
//Schema definition
const Schema= mongoose.Schema;
const BookSchema=new Schema({
title: String,
author: String,
genre: String,
// image: String,
image:{
data: Buffer,
contentType: String
}
});
//Model creation
var Bookdata= mongoose.model('bookdata',BookSchema);
module.exports=Bookdata;
and this is my .ejs file
<%for(i=0;i<books.length;i++){%>
<div class="row">
<br>
<div class="col-md-2 col-sm-3 text-center">
<a class="story-title" href="#">
<img src="data:<%=books[i].image.contentType%>;base64,{Buffer.from('<%=books[i].image.data%>','binary').toString('base64')}" style="width:100px;height:100px" class="img-circle">
</a>
</div>
my get function
booksRouter.get('/',function(req,res){
Bookdata.find()
.then(function(books){
res.render("books",{
nav,
title:"Library App",
books
});
})
});
in mongodb, i am getting like this
> _id:6226e5c60e92bdee82dc574a title:"cc" author:"aa" genre:"life" image:Object
> data:Binary('iVBORw0KGgoAAAANSUhEUgAAA+gAAAOECAYAAAAylRvFAAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAAgY0hSTQAAeiYA...',
> 0) contentType:"image/png"
> __v:0
In Console i am getting error
GET data:image/png;base64,{Buffer.from('%EF%BF%BDPNG%0A%1A%0A%EF%BF%BD%EF%BF%BD%EF%BF%BD%0AIHDR%EF%BF%BD%EF%BF%BD%03%EF%BF%BD%EF%BF%BD%EF%BF%BD%03%EF%BF%BD%08%06%EF%BF%BD%EF%BF%BD%EF%BF%BD2%EF%BF%BD%1B%EF%BF%BD%EF%BF%BD%EF%BF%BD%EF%BF%BD%04gAMA%EF%BF%BD%EF%BF%BD%EF%BF%BD%EF%BF%BD%0B%EF%BF%BDa%05%EF%BF%BD%EF%BF%BD%EF%BF%BD%01sRGB%EF%BF%BD%EF%BF%BD%EF%BF%BD%1C%EF%BF%BD%EF%BF%BD%EF%BF%BD%EF%BF%BD cHRM%EF%BF%BD%EF%BF%BDz&%EF%BF%BD%EF%BF%BD%EF%BF%BD%EF%BF%BD%EF%BF%BD%EF%BF%BD%EF%BF%BD%EF%BF%BD%EF%BF%BD%EF%BF%BD%EF%BF%BD%EF%BF%BD%EF%BF%BD%EF%BF%BDu0%EF%BF%BD%EF%BF%BD%EF%BF%BD`%EF%BF%BD%EF%BF%BD:%EF%BF%BD%EF%BF%BD%EF%BF%BD%17p%EF%BF%BD%EF%BF%BDQ<%EF%BF%BD%EF%BF%BD%EF%BF%BD%06bKGD%EF%BF%BD%EF%BF%BD%EF%BF%BD%EF%BF%BD%EF%BF%BD%EF%BF%BD%EF%BF%BD%EF%BF%BD%EF%BF%BD%EF%BF%BD%EF%BF%BD%EF%BF%BD%EF%BF%BD%09pHYs%EF%BF%BD%EF%BF%BD%0E%EF%BF%BD%EF%BF%BD%EF%BF%BD%0E%EF%BF%BD%01%EF%BF%BD+%0E%1B%EF%BF%BD%EF%BF%BD%EF%BF%BD%EF%BF%BDIDATx%EF%BF%BD%EF%BF%BD%EF%BF%BDW%EF%BF%BD$%D7%95%EF%BF%BD%09%EF%BF%BDk%EF%BF%BDp%1D%1EZ%EF%BF%BD%EF%BF%BDH(%EF%BF%BD*%16g%EF%BF%BD%EF%BF%BD%EF%BF%BDNWw%EF%BF%BD%EF%BF%BDy%EF%BF%BDb.%EF%BF%BDb~%EF%BF%BD%EF%BF%BDI%EF%BF%BDb.%EF%BF%BD3]%EF%BF%BDd%15%EF%BF%BD$HB%%EF%BF%BDD%EF%BF%BD%EF%BF%BD%EF%BF%BD%D2%B5%EF%BF%BD%EF%BF%BD%EF%BF%BD%EF%BF%BD%EF%BF%BD%EF%BF%BD%EF%BF%BDEDF&%EF%BF%BDV%01H%10%EF%BF%BD%EF%BF%BD%13%EF%BF%BD%08ws%EF%BF%BD%EF%BF%BD%EF%BF%BD%EF%BF%BD%EF%BF%BDk%EF%BF%BDo%EF%BF%BD%EF%BF%BD*%1E%EF%BF%BD%EF%BF%BD%EF%BF%BD%EF%BF%BDx<%1E%EF%BF%BD%EF%BF%BD%EF%BF%BD%EF%BF%BDx%EF%BF%BDW%EF%BF%BD?%05%1E%EF%BF%BD%EF%BF%BD%EF%BF%BD%EF%BF%BDx%3C%1E%EF%BF%BD%EF%BF%BD%EF%BF%BD%EF%BF%BD|%EF%BF%BDx%EF%BF%BD%EF%BF%BD%EF%BF%BDx%3C%1E%EF%BF%BD%EF%BF%BD%EF%BF%BD%EF%BF%BDx%3C%1E%EF%BF%BD%1B%EF%BF%BD%17%EF%BF%BD%1E%EF%BF%BD%EF%BF%BD%EF%BF%BD%EF%BF%BDx%3C%1E%EF%BF%BD%EF%BF%BD%EF%BF%BD%EF%BF%BD%01x%EF%BF%BD%EF%BF%BD%EF%BF%BDx%3C%1E%EF%BF%BD%EF%BF%BD%EF%BF%BD%EF%BF%BDx%3C%1E%EF%BF%BD%1B%EF%BF%BD%17%EF%BF%BD%1E%EF%BF%BD%EF%BF%BD%EF%BF%BD%EF%BF%BDx%3C%1E%EF%BF%BD%EF%BF%BD%EF%BF%BD%EF%BF%BD%01x%EF%BF%BD%EF%BF%BD%EF%BF%BDx%3C%1E%EF%BF%BD%EF%BF%BD%EF%BF%BD%EF%BF%BDx%3C%1E%EF%BF%BD%1B%EF%BF%BD%17%EF%BF%BD%1E%EF%BF%BD%EF%BF%BD%EF%BF%BD%EF%BF%BDx%3C%1E%EF%BF%BD%EF%BF%BD%EF%BF%BD%EF%BF%BD%01x%EF%BF%BD%EF%BF%BD%EF%BF%BDx%3C%1E%EF%BF%BD%EF%BF%BD%EF%BF%BD%EF%BF%BDx%3C%1E%EF%BF%BD%1B%EF%BF%BD%17%EF%BF%BD%1E%EF%BF%BD%EF%BF%BD%EF%BF%BD%EF%BF%BDx%3C%1E%EF%BF%BD%EF%BF%BD%EF%BF%BD%EF%BF%BD%01%EF%BF%BD%EF%BF%BD%14%EF%BF%BD0%EF%BF%BD%EF%BF%BD%7F%02%EF%BF%BD%EF%BF%BD%EF%BF%BD%EF%BF%BD%0B%EF%BF%BD0%EF%BF%BDY\5%7F_D%EF%BF%BD%EF%BF%BD%EF%BF%BDx%3C%1E%EF%BF%BD%EF%BF%BD%EF%BF%BD%EF%BF%BDx%3C%EF%BF%BD%EF%BF%BD%EF%BF%BD%D1%B1%12%EF%BF%BD%EF%BF%BD%EF%BF%BDP%D0%B1%10%EF%BF%BD%19%11-S%EF%BF%BD-%EF%BF%BD%12%EF%BF%BD%EF%BF%BD%EF%BF%BD%13E%EF%BF%BDg%EF%BF%BD%EF%BF%BDYa%3E^%EF%BF%BD%EF%BF%BD%C5%BA%EF%BF%BD%EF%BF%BD%EF%BF%BDx%3C%1E%EF%BF%BD%EF%BF%BD%EF%BF%BD%EF%BF%BD|[%EF%BF%BD%08%EF%BF%BD%0F%EF%BF%BD%EF%BF%BD%08%EF%BF%BD%EF%BF%BD%08W%EF%BF%BD%0Bt=%EF%BF%BD%EF%BF%BDL%EF%BF%BD%EF%BF%BD%CC%AEjf%EF%BF%BD%EF%BF%BDB%EF%BF%BD%0Bs%EF%BF%BD%EF%BF%BD%EF%BF%BD%EF%BF%BDx%3C%1E%EF%BF%BD%EF%BF%BD%EF%BF%BD%EF%BF%BD%EF%BF%BD%EF%BF%BD%11%EF%BF%BD%1F,%EF%BF%BD*(%02%EF%BF%BDKx&%EF%BF%BD.Lb%EF%BF%BD%0A%EF%BF%BD+%DE%90|A%EF%BF%BD%EF%BF%BD%EF%BF%BD%22/e%C3%8F%EF%BF%BD%EF%BF%BD%17%EF%BF%BD%1E%EF%BF%BD%EF%BF%BD%EF%BF%BD%EF%BF%BDx%3C%1E%EF%BF%BD%EF%BF%BD%EF%BF%BD]%EF%BF%BD net::ERR_INVALID_URL
my mongodb
in the template, just add the properties:
edit: Buffer.from is not needed, as it's already a buffer:
with for loop:
<%for(i=0;i<books.length;i++){%>
<div class="row">
<br>
<div class="col-md-2 col-sm-3 text-center">
<a class="story-title" href="#">
<img src="data:<%=books[i].image.contentType%>;base64,<%=books[i].image.data.toString('base64')%>" style="width:100px;height:100px" class="img-circle">
</a>
</div>
<% } %>

file upload with axioso is showing undefined in multer

I am trying to upload file using react and axios to node backend using multer.
when i use form as :
<form action = '/article/add' method="POST" className = {adminStyle.add_article_form} enctype="multipart/form-data">
<input type='text' className={adminStyle.add_article_input_title} autoComplete = 'off' name='title' placeholder='Title' value = {state.title} onChange={changeHandler}/>
<select name='category' value = {state.category} onChange={changeHandler}>
{options}
</select>
<input type="file" name='thumbnail' className={adminStyle.add_article_input_file} onChange={changeFileHandler}/>
<textarea type = 'text' name='body' className={adminStyle.add_article_textarea} rows='30' cols='100' value = {state.body} onChange={changeHandler}></textarea>
<button type='submit'>Submit</button>
</form>
it works fine but when using axios the file is undefined:
I used axios as:
const [state,setState] = useState({
title: '',
category: 'Choose one',
body: '',
thumbnail: ''
})
const changeFileHandler = (e) => {
setState({ thumbnail: e.target.files[0] })
}
const postArticle = (e) => {
e.preventDefault();
const formData = new FormData();
formData.append('thumbnail', state.thumbnail)
axios.post('/article/add', state,config).then(data => console.log(data))
}
<form onSubmit={postArticle} className = {adminStyle.add_article_form} enctype="multipart/form-data">
<input type='text' className={adminStyle.add_article_input_title} autoComplete = 'off' name='title' placeholder='Title' value = {state.title} onChange={changeHandler}/>
<select name='category' value = {state.category} onChange={changeHandler}>
{options}
</select>
<input type="file" name='thumbnail' className={adminStyle.add_article_input_file} onChange={changeFileHandler}/>
<textarea type = 'text' name='body' className={adminStyle.add_article_textarea} rows='30' cols='100' value = {state.body} onChange={changeHandler}></textarea>
<button type='submit'>Submit</button>
</form>
My backend is as follow:
const storage = multer.diskStorage({
destination: path.join(__dirname, '..', '../public/uploads'),
filename: function(req, file, cb){
cb(null,file.fieldname + '-' + Date.now() + path.extname(file.originalname));
}
});
function checkFileType(file, cb){
// Allowed extension name
const filetypes = /jpeg|jpg|png|gif/;
// Check ext
const extname = filetypes.test(path.extname(file.originalname).toLowerCase());
const mimetype = filetypes.test(file.mimetype);
if(mimetype && extname){
return cb(null,true);
} else {
cb('Error: Images Only!');
}
}
const upload = multer({
storage: storage,
limits:{fileSize: 1000000},
fileFilter: function(req, file, cb){
checkFileType(file, cb);
}
}).single('thumbnail')
router.post('/add',(req, res)=>{
upload(req,res, (err) => {
console.log(req.file)
})
});
can anyone help me with this? I am really stuck. I need to upload the image in the backend.
You are passing state and not formData as the body of the request. You should change this line:
axios.post('/article/add', state,config).then(data => console.log(data))
with this line:
axios.post('/article/add', formData ,config).then(data => console.log(data))

How to upload multiple file with react/node and multer

I'm trying to upload multiple files with React/express and multer. But can't find what's wrong in my code...(I tried many solutions that I found here but I can't see where I'm wrong).
Here is my code :
**Front : **
function App() {
const [file, setFile] = useState(null);
const handleSubmit = async (e) => {
e.preventDefault();
const formData = new FormData();
let newArr = [];
for (let i = 0; i < file.length; i++) {
newArr.push(file[i]);
}
formData.append('monfichier', newArr);
console.log(formData.get('monfichier'));
axios
.post('http://localhost:3000/uploaddufichier', formData)
.then((res) => res.data);
};
return (
<div className='App'>
<form
onSubmit={handleSubmit}
method='POST'
encType='multipart/form-data'
action='uploaddufichier'
>
<input
type='file'
name='monfichier'
onChange={(e) => setFile(e.target.files)}
multiple
/>
<button> envoyer </button>
</form>
</div>
enter code here
BACK
const multer = require('multer');
const fs = require('fs');
const cors = require('cors');
const path = require('path');
const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, 'file-storage');
},
filename: function (req, file, cb) {
cb(null, file.fieldname + '-' + Date.now());
},
});
const upload = multer({ storage: storage });
app.use(express.json());
app.use(router);
app.use(cors());
app.use('/file-storage', express.static('file-storage'));
app.use(function (err, req, res, next) {
console.log('This is the invalid field ->', err.field);
next(err);
});
app.post(
'/uploaddufichier',
upload.array('monfichier'),
function (req, res, next) {
console.log(req.files);
fs.rename(
req.files.path,
'file-storage/' + req.files.originalname,
function (err) {
if (err) {
res.send('problème durant le déplacement');
} else {
res.send('Fichier uploadé avec succès');
}
}
);
}
);
For now the back-end console.log(req.files) return an empty array...
And the front-end console.log(formData.get('monfichier') return [object File], [object File]
IF anyone could help me for that issue....It'll be glad :)
A small tweak would have fixed it let me fix it and highlight the tweak that will fix it below.
function App() {
const [file, setFile] = useState(null);
const handleSubmit = async (e) => {
e.preventDefault();
const formData = new FormData();
let newArr = [];
//********* HERE IS THE CHANGE ***********
for (let i = 0; i < file.length; i++) {
formData.append('monfichier', file[i]);
}
console.log(formData.get('monfichier'));
axios
.post('http://localhost:3000/uploaddufichier', formData)
.then((res) => res.data);
};
return (
<div className='App'>
<form
onSubmit={handleSubmit}
method='POST'
encType='multipart/form-data'
action='uploaddufichier'
>
<input
type='file'
name='monfichier'
onChange={(e) => setFile(e.target.files)}
multiple
/>
<button> envoyer </button>
</form>
</div>
The array method on multer accepts multiple files over the wire provided they have the corresponding name you specified (in our case 'monfichier'). So what we have done with the for-loop on the front-end is append several files with the same name - monfichier.
This question has been unanswered for 9months but hopefully, it will be helpful to you or anyother person that is facing this blocker.
#cheers
I know this is an old question, however, this solution will be useful to anyone who is experiencing a similar challenge.
The solution is simple. You must attach your photos with the same name on the frontend. then sending them to the backend. The rest will be handled by Multer, and you can access your files via 'req.files'.
Example
React
const formData = new FormData();
for (let i = 0; i < event.target.files.length; i++) {
formData.append("images", event.target.files[i]);
}
fetch("http://localhost:3003/api/v1/upload", {
method: "POST",
body: formData,
});
};
Backend - ExpressJs + Multer
gallaryRouter
.route("/:galleryId")
.post(
UploadGallery.array("images"),
(req,res)=>{console.log(req.files)}
)

Inserting Data into phpmyadmin using node.js express and reactjs

I have a table in my database called products and I am trying to insert into in using node.js express server as the web service and react.js as the front-end language.
Below is my react.js form to perform the insertion.
function App() {
return (
<div className="container">
<form onSubmit = {(e) => Add(e)}>
<div className="form-group">
<label htmlFor="examplePname">Name</label>
<input type="text" className="form-control" id="examplePname" aria-describedby=""/>
</div>
<div className="form-group">
<label htmlFor="examplePprice">Price</label>
<input type="number" className="form-control" id="examplePprice"/>
</div>
<div className="form-group form-check">
<input type="checkbox" className="form-check-input" id="exampleCheck1"/>
<label className="form-check-label" htmlFor="exampleCheck1">Check me out</label>
</div>
<button type="submit" className="btn btn-primary">Submit</button>
</form>
</div>
);
}
function Add(e){
e.preventDefault();
let request = {
name: document.getElementById('examplePname').value,
price: document.getElementById('examplePprice').value,
}
alert("returns this:"+ request)
axios.post('http://localhost:3000/add', request)
.then(resp => {
alert(resp.data.message);
})
.catch(err => {
console.log(err);
})
}
Below is my node.js express Webservice
router.post('/add', (req, res) => {
const {name, price} = req.query;
console.log(name, price); ///Do this before you write the insert query
//res.send('adding product');Do this before you write the insert query (add temp products to view in cmd)
const INSERT_QUERY = `INSERT INTO products (name, price) VALUES('${name}', ${price})`; //after do an insert query to add to db proper
connection.query(INSERT_QUERY, (err, results) => {
if (err) {
return res.send({
message: "failed"
})
} else {
return res.send({
message: "successful"
});
}
});
});
But when I insert I get undefined values for both name and price in console.log.
Use Below code in app.js in node side for parsing parameter
const bodyparser = require('body-parser');
const multer = require('multer');
//Multer
var storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, './Images');
},
filename: function (req, file, cb) {
let fileType = file.originalname.split('.');
cb(null, `${fileType[0]}_${Date.now()}.${fileType[1]}`);
}
})
var upload = multer({ storage: storage });
app.use(upload.any());
// Parse
app.use(bodyparser.json({ limit: '50mb', extended: true }));
app.use(bodyparser.urlencoded({ limit: '50mb', extended: true, parameterLimit: 1000000 }));
Please install above dependencies before restart the server
React side send form data as below
createFormData(props) {
var formData = new FormData();
for (var key in props) {
if (typeof props[key] === "string" || props[key] instanceof Date) {
formData.append(key, props[key]);
}
else if (typeof props[key] === "object") {
if (Array.isArray(props[key]) && key === "file") {
//Multiple File Upload
props[key].length > 0 && props[key].forEach((element) => {
if (element.lastModifiedDate) {
formData.append(key, element);
}
})
}
else if (props[key] && props[key].lastModifiedDate) {
//Single File Upload
formData.append(key, props[key]);
} else {
formData.append(key, JSON.stringify(props[key]));
}
} else {
formData.append(key, JSON.stringify(props[key]));
}
}
return formData;
}
// Axios Request
axios({
url: url here,
method: 'POST',
data: this.createFormData(your form data object),
timeout: 30000
}).then(response => {
if (response.status === 200) {
}
})
you will get data as follow at node side
let data = { ...req.body, ...req.params, ...req.query }

How to insert and retrieve video from mongodb in node js

I new to mean stack. I want to upload video to mongodb and then I want to retrieve it.
this is app.js file
`const express = require('express');
const bodyParser = require('body-parser');
const path = require('path');
const crypto = require('crypto');
const mongoose = require('mongoose');
const multer = require('multer');
const GridFsStorage = require('multer-gridfs-storage');
const Grid = require('gridfs-stream');
const methodOverride = require('method-override');
const app = express();
// Middleware
app.use(bodyParser.json());
app.use(methodOverride('_method'));
app.set('view engine', 'ejs');
// Mongo URI
const mongoURI = 'mongodb://fawad:Fawad123#ds155243.mlab.com:55243/imageupload';
// Create mongo connection
const conn = mongoose.createConnection(mongoURI);
// Init gfs
let gfs;
conn.once('open', () => {
// Init stream
gfs = Grid(conn.db, mongoose.mongo);
gfs.collection('uploads');
});
// 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: 'uploads'
};
resolve(fileInfo);
});
});
}
});
const upload = multer({ storage });
// #route GET /
// #desc Loads form
app.get('/', (req, res) => {
gfs.files.find().toArray((err, files) => {
// Check if files
if (!files || files.length === 0) {
res.render('index', { files: false });
} else {
files.map(file => {
if (
file.contentType === 'video/mp4' ||
file.contentType === 'video/webm '
) {
file.isVideo = true;
} else {
file.isVideo = false;
}
});
res.render('index', { files: files });
}
});
});
// #route POST /upload
// #desc Uploads file to DB
app.post('/upload', upload.single('file'), (req, res) => {
// res.json({ file: req.file });
res.redirect('/');
});
// #route GET /files
// #desc Display all files in JSON
app.get('/files', (req, res) => {
gfs.files.find().toArray((err, files) => {
// Check if files
if (!files || files.length === 0) {
return res.status(404).json({
err: 'No files exist'
});
}
// Files exist
return res.json(files);
});
});
// #route GET /files/:filename
// #desc Display single file object
app.get('/files/:filename', (req, res) => {
gfs.files.findOne({ filename: req.params.filename }, (err, file) => {
// Check if file
if (!file || file.length === 0) {
return res.status(404).json({
err: 'No file exists'
});
}
// File exists
return res.json(file);
});
});
// #route GET /image/:filename
// #desc Display Image
app.get('/video/:filename', (req, res) => {
gfs.files.findOne({ filename: req.params.filename }, (err, file) => {
// Check if file
if (!file || file.length === 0) {
return res.status(404).json({
err: 'No file exists'
});
}
// Check if image
if (file.contentType === 'video/mp4' || file.contentType === 'video/webm') {
// Read output to browser
const readstream = gfs.createReadStream(file.filename);
readstream.pipe(res);
} else {
res.status(404).json({
err: 'Not an image'
});
}
});
});
// #route DELETE /files/:id
// #desc Delete file
app.delete('/files/:id', (req, res) => {
gfs.remove({ _id: req.params.id, root: 'uploads' }, (err, gridStore) => {
if (err) {
return res.status(404).json({ err: err });
}
res.redirect('/');
});
});
const port = 9000;
app.listen(port, () => console.log(`Server started on port ${port}`));
`
index.ejs
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm"
crossorigin="anonymous">
<style>
video {
width: 100%;
}
</style>
<title>Mongo File Uploads</title>
</head>
<body>
<div class="container">
<div class="row">
<div class="col-md-6 m-auto">
<h1 class="text-center display-4 my-4">Mongo File Uploads</h1>
<form action="/upload" method="POST" enctype="multipart/form-data">
<div class="custom-file mb-3">
<input type="file" name="file" id="file" class="custom-file-input">
<label for="file" class="custom-file-label">Choose File</label>
</div>
<input type="submit" value="Submit" class="btn btn-primary btn-block">
</form>
<hr>
<% if(files){ %>
<% files.forEach(function(file) { %>
<div class="card card-body mb-3">
<% if(file.isVideo) { %>
<video src="video/<%= file.filename %>" alt="">
<% } else { %>
<%= file.filename %>
<% } %>
<form method="POST" action="/files/<%= file._id %>?_method=DELETE">
<button class="btn btn-danger btn-block mt-4">Delete</button>
</form>
</div>
<% }) %>
<% } else { %>
<p>No files to show</p>
<% } %>
</div>
</div>
</div>
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN"
crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q"
crossorigin="anonymous"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl"
crossorigin="anonymous"></script>
</body>
</html>
this code work for image..when I used (file.contentType = image/png).
but for video it's not working.. is Image and video upload are same?
You can use Formidable. As It support multipart data. And for retrieve video you can use fs(file system)
Actually you don't save media(image or video) in DB, you store it in some storage drive(locally or cloud) like s3 bucket, and then store its location url in your DB.
and this code might be helpful.
saveImage(urlPath, folderPath, multiple) {
return new Promise((resolve, reject) => {
var timestamp = Date.now();
var filepath = urlPath;
var imageUrl;
var ext = path.extname(filepath || '').split('.');
var extension = ext[ext.length - 1];
var tmp_path = filepath;
imageUrl = folderPath + timestamp + '.' + extension;
if (multiple != '' && multiple != undefined) { imageUrl = folderPath + timestamp + multiple + '.' + extension; }
var target_path = __dirname + '/../' + imageUrl;//Change according to your location.
console.log("target_path", target_path);
mv(tmp_path, target_path, { mkdirp: true }, function (err) { })
return resolve({ status: 1, url: imageUrl });
})
}
Now, urlPath is your media path, foldarPath is path where you want to store your media and multiple is to give unique name.
you can call this method like this.
var multiple = Number(0) + Number(10);
console.log("multiple", multiple);
var saveImage = await 'YOUR_FILE_NAME'.saveImage(files.photo[0].path, 'public/Image/', multiple);
console.log(saveImage);
<video src="video/<%= file.filename %>" controls alt="">
//Try adding the controls command in the video tag. It helps the video run.

Resources