I'm trying to dynamically create folders when user loads a file (this is because I need to store every user files separately so there's no conflict if a file is deleted) and create the file path in my computer so I can store it in my many to many relationship table in the database (users can have many files and many files can belong to different users, that's why I can't store them together) but I cannot get this with my current logic. I could create different name with timestamps but it would get messy.
I'm using multer and Express. The form data that's been sent is the one on the attached image.
const express = require('express');
const app = express();
const multer = require('multer');
const bodyParser = require('body-parser');
const fs = require('fs');
router.use(bodyParser.json());
router.use(bodyParser.urlencoded({ extended: false }));
let storage = multer.diskStorage({
destination: function (req, file, cb) {
//req.body is empty
let path = `./public/uploads/${req.body.id}`;
if (!fs.existsSync(path)) {
fs.mkdirSync(filesDir);
}
cb(null, path);
},
filename: function (req, file, cb) {
cb(null, `${file.originalname}`)
}
})
let upload = multer({storage:storage});
var cpUpload = upload.fields([{ name: 'file', maxCount: 1}, { name: 'id'}]);
router.post('/uploadSingFile', cpUpload,(req,res)=>{
console.log(req.body); req.body is ok
res.send({status:200});
});
Somehow the request object doesn't have the body in the destination function but does in the post request. I thought this would work given the way middlewares work in Node, the storage function should have the same request object that the post request has.
You can use newly generated uuid for filenames to have it unique inside the folder. For the folder name, instead of getting it from request body(req.body.id), use something like userId which can make sure the folder belongs to particular user.
Related
I am tying to store a form data along with files. when I am use form without this enctype="multipart/form-data" works fine but req.files dosent exist in req which i need to upload files. and when i use enctype in form, still req.files dosent exist and req.body does not have any data.
I was trying to implement multer to handle files but req.files dosent exist so didnt get any idea.
my route
const urlencodedParser = bodyParser.urlencoded({extended: true});
router.post('/save_file', urlencodedParser, home.add_file);
my controller
exports.add_file = function(req, res){
console.log(req.body);
console.log(req.files);
}
Any help will be appriciated.
bodyParser, the library you use to parse your request from the server, doesn't parse files, you need to use another library, (multer is very good and easy).
So first :
Install Multer: npm install multer --save
Here the link of Multer: https://github.com/expressjs/multer
Use this example as base:
let multer = require("multer"); //the library
let storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, 'path/to/upload/your/file');
},
filename: function (req, file, cb) {
cb(null, file.originalname);
}
});//Configure the place you will upload your file
let upload = multer({ storage: storage }); //instanciation of multer
// image is the name of the input in the form
router.post('/your_endpoint', upload("image"), (req, res)=> {
let file = req.file; //contains the file
let path = file.path; //contains the paths
})
Try using multer in your node app -
https://www.npmjs.com/package/multerenter link description here
Multer takes the files i upload and puts it inside the file object so we can access it through the file but then the req.body.image is empty and i want to be able to pass the file.originalname to the req.body.image as path to the stored disk location. Now, i am working with multiple file here so i want to store their paths in the req object and access it inside another middle ware.
I tried something like this
req.body.image.push(`path/${file.originalname}`)
which returns an error
TypeError: Cannot read property 'push' of undefined
TypeError: Cannot read property 'push' of undefined
It looks like req.body.image isn't an Array but undefined when you're using push().
When multer adds a single file to the request object, it adds them to the req.file property. You can then access req.file in subsequent middleware like in the below example. If you have multiple uploaded files then you would access the File Array req.files and iterate through the collection to access each file object.
In your above code, you're modifying the req.body object and adding the property image, I wouldn't recommend changing the req.body object. It is good practice to not mutate things like the request headers or body. Instead, you can add a new property req.image to the request object.
The below example uses Router Middleware to encapsulate the upload logic, (which should be kept to a single route usually) and then adds that middleware to an Express Server.
imageUploadRouter.js
// imageUploadRouter.js
const router = require('express').Router()
const multer = require('multer')
const upload = multer({dest: 'uploads/'})
router.use(upload.single('image'))
router.use((req, res, next) => {
if (!Array.isArray(req.image)) {
req.image = []
}
if (req.file) {
req.image.push(`path/${req.file.originalName}`)
}
return next()
})
// add some additional routes for logic
router.post('/', (req, res) => {
// do something and respond
// you can access req.image here too
return res.sendStatus(201)
})
module.exports = router
server.js
// server.js
const express = require('express')
const ImageUploadRouter = require('./imageUploadRouter')
const server = new Express()
const port = process.env.PORT || 1337
server.use('/images', ImageUploadRouter)
server.listen(port, () => console.log(`Lisening on ${port}`))
I am creating a simple application as a learning experience with ionic 2 that connects to a node server running multer to upload images. The problem I am running into is, I need to get the final file name from multer back to the app that uploaded it, to save it locally. I am using the Auth and User modules from #ionic/cloud-angular for authentication and user information. The User object has a details object with things like "name", "email", "username", "image", ...
So, when an image is uploaded to the node server and multer saves it, I need to get that filename back to the application so I can update the user.details.image property.
Here is a simple version of my node server...
var express = require('express');
var http = require('http');
var bodyParser = require('body-parser');
var multer = require('multer');
var cors = require('cors');
var postStorage = multer.diskStorage({
destination: function(req, file, callback) {
callback(null, './uploads');
},
filename: function(req, file, callback) {
let fileName = '', postName;
if(typeof req.body.postName !== "undefined") {
postName = req.body.postName.toLowerCase().replace(/ /g, '-');
filename += postName;
}
fileName += new Date().getTime();
fileName += ".png";
callback(null, fileName);
}
});
var app = express();
app.set('port', process.env.PORT || 3000);
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: false}));
app.use(cors());
app.post('/upload', function(req, res) {
var uploadPost = multer({storage: postStorage}).single('post_image');
uploadPost(req, res, function(err) {
if(err) {
return res.end("error uploading file");
}
res.end("file uploaded");
});
});
app.listen(app.get('port');
console.log("app listening on port: " _ app.get('port'));
Is there a way to have it send back the final file name that multer saved? Something like res.json({fileName: fileName}); res.end();
I really don't know at this point, and all the tutorials I can find on multer just show how to create a new filename and save a file in disk or database or memory, but nowhere does it show how you can actually get that filename back to the application that uploaded it.
Thank you in advance for any help, I really appreciate it. If you need to see the ionic 2 code that uploads the stuff please let me know and I will update the post with that code as well. Thank you.
If you are uploading single file you can get filename using req.file.filename
if you upload multiple files req.files
Once you got file name , you can send it to client using res.send({filename:FileName});
I have gotten this far to accept a file in my HTML form and post in with angular via an $http.post using the ng-file-upload module. Now I want to accept this file in Mongoose and store it into my NoSQL MongoDB hosted on MongoLab.
I have read about this module called Multer and followed the basic documentation, but it only me as far. Before I explain the beginning of the problem let me post my Code:
My HTML form:
<form name="upForm">
<fieldset>
<legend>Upload files here</legend>
<label>Insert File Here:</label>
<input type="file" ngf-select ng-model="exFile" name="file" ngf-accept="'.cs'" required>
<i ng-show="upForm.file.$error.required">*required</i>
<div class="alert" ng-show="file.$error === 'pattern'">
file type is not accepted
</div>
<br />
<button ng-disabled="!upForm.$valid" ng-click="uploadExercise(exFile)" class="btn btn-default">Submit</button>
<span class="progress" ng-show="picFile.progress >= 0">
<div style="width:{{exFile.progress}}%" ng-bind="picFile.progress + '%'"></div>
</span>
<span ng-show="picFile.result">Upload Successful</span>
</fieldset>
</form>
My Angular Code:
$scope.uploadExercise = function (file) {
console.log(file);
var fd = new FormData();
fd.append('file', file);
$http.post(url+"/Upload", fd,{
transformRequest: angular.identity,
header:{'Content-Type': undefined},
enctype:'multipart/form-data'
}).success(function () { }).error(function () { });
console.log(fd);
};
console logs return the correct file objects.
Mongoose so far:
var mongoose = require("mongoose");
var express = require("express");
var multer = require('multer');
var upload = multer({ dest: 'Uploads/' });
var bodyparser = require("body-parser");
var app = express();
mongoose.connect("connection-string");
app.use(bodyparser.json());
app.post('/Upload', upload.single('solution') ,function (req, res, next) {
console.log(req.file);
});
This console.log keeps returning undefined. So something, somewhere went terribly wrong. Please help me out!
I want to receive this file in my Mongoose and store it into the MongoDB, I have never done this before and can't seem to find any decent documentation for Multer or any decent explanation for storing files that is relevant for my case. What am I doing wrong? What should I be doing instead?
Man you are running on the wrong path. I have already explained in your previous question request that Multer is used to save files in file disk system and not to your database directly. For that you must use GRIDFS.
Coming to your current question.
app.post('/Upload', upload.single('solution') ,function (req, res, next) {
console.log(req.file);
});
Here the upload.single('solution') - calls a function Upload and the file name passed is solution but it is obvious enough that it isn't available here.
use this type of format - documentation of Multer
var storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, '/tmp/my-uploads')
},
filename: function (req, file, cb) {
cb(null, file.fieldname + '-' + Date.now())
}
})
var upload = multer({ storage: storage })
The Storage Part there is used to give path to where your file must be saved and the file name section is used to make changes to the file name that you would like to have.
Please read the documentation because that'll help. When we use third party modules we must acknowledge the information they have already given so that we can use their work easily.
Let me make it easier for you. Here is ready made code that works.
Multer throwing weird error while uploading file via ng-file upload
Go check that thread. The question was raised by me - the problem there was I was sending files in array format, as in multiple files at once. If you are not doing that just change ng-file-upload segment to use the single upload demo example and on server side nodejs code replace .array with .singleand things will work the way you want them to work - given that you want to use file disk system to store files.
I repeat that this method wont help you to save the file in mongodb directly.
Let me know if you need any further clarification.
After some research I found the answer to my problem. I'm able to store files into my MongoDB now. For those who are interested I'm posting my Mongoose code below with a small description.
Start by installing packages required for this operation. I used the following ones
npm install --save formidable
npm install --save gridfs
npm install --save fs
these are the packages I used ( Formidable, gridfs and fs).
this is the fully working mongoose code for me relevant to this particular form and request.
var mongoose = require("mongoose");
var express = require("express");
var formidable = require("formidable");
var fs = require("fs");
var grid = require("gridfs-stream");
var bodyparser = require("body-parser");
var app = express();
mongoose.connect("**fill in your connection-url here**");
var conn = mongoose.connection;
app.use(bodyparser.json());
app.post('/Upload', function (req, res) {
var form = new formidable.IncomingForm();
form.uploadDir = __dirname+"/Uploads";
form.keepExtensions = true;
form.parse(req, function (err, fields, files) {
if (!err) {
console.log('Files Uploaded: ' + files.file)
grid.mongo = mongoose.mongo;
var gfs = grid(conn.db);
var writestream = gfs.createWriteStream({
filename: files.file.name
});
fs.createReadStream(files.file.path).pipe(writestream);
}
});
form.on('end', function () {
res.send('Completed ... go check fs.files & fs.chunks in mongodb');
});
});
this worked for me! I now went to look in my mongoDB hosted on MongoLab and see that fs.chunks and fs.files collections were created and fs.files contains the correct data.
So for those who have this problem, this is a solution and the documentation on http://excellencenodejsblog.com/gridfs-using-mongoose-nodejs/ helped me out a lot. Now that I have this working, I also want to download the file FROM mongoDB onto a chosen directory on my pc, is there anyone who can give me the answer to that? or is that just as simple as to create a readstream to a file-system?
I am trying to build a Node.js Application in Express.js 4 that uploads an image. I decided to use the multer module but cannot access the uploaded file through req.files.
Here Is the code I am using. I restricted it to those parts that I believe are relevant.
Jade code:
form(method="POST", action="createPost", enctype="multipart/form-data")
input(type="file", name="photo")
br
input(type="submit" value="upload")
in routes/admin.js:
var express = require('express');
var multer = require('multer');
var router = express.Router();
var upload = multer({dest: './uploads/'});
router.post('/createPost', upload.single('photo'), function(req, res, next) {
console.log('files:', req.files);
console.log('body:', req.body);
// more code
}
output:
files: undefined
body: {}
The file is stored in the uploads folder but I cannot access its information in req.files. Can anyone help me?
When using upload.single(), per the multer documentation, the resulting file should be in req.file, not req.files. See the example in their doc here.
app.post('/profile', upload.single('avatar'), function (req, res, next) {
// req.file is the `avatar` file
// req.body will hold the text fields, if there were any
})
And, here's the actual doc for upload.single():
.single(fieldname)
Accept a single file with the name fieldname. The single file will be
stored in req.file.