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?
Related
I'm trying to create a page that lets you upload a file to a folder and say what a number is in an input. I'm new to the multer library(which is what I'm using right now) and I usually use body-parser. Here is my app.js and my upload.ejs, I'll explain what my problem is below it.
app.js
const express = require('express');
const http = require('http');
const formidable = require('formidable');
const fs = require('fs');
const ejs = require('ejs')
const path = require('path');
const multer = require('multer');
const upload = multer({ dest: 'upload/'});
const type = upload.any('gradeNumber');
const app = express();
app.use(express.static(__dirname + '/public'));
app.set('view engine', 'ejs');
app.get('/fileupload', function (req, res) {
res.render("upload")
});
app.post('/fileupload',type, function (req, res) {
const form = new formidable.IncomingForm();
console.log(req.body.gradeNumber);
form.parse(req, function (err, fields, files) {
const oldpath = files.filetoupload.path;
const newpath = 'C:/Users/Shubh Computer/Desktop/VSCode/Grades/1/' + files.filetoupload.name;
fs.rename(oldpath, newpath, function (err) {
if (err) throw err;
res.write('File uploaded and moved!');
res.end();
});
});
});
app.listen(3000);
upload.ejs
<!DOCTYPE html>
<html>
<head>
<title>Upload File</title>
</head>
<body>
<form action="fileupload" method="post" enctype="multipart/form-data">
<input type="file" name="filetoupload"><br>
<label>What Grade</label><input type="text" name="gradeNumber"><br>
<input type="submit">
</form>
</body>
</html>
Before I started to use multer, I was uploading the file to a specific folder without error, but would get the input value as undefined. After I added the app.post(/fileupload,type,function(req,res){}) I can log the input but can't upload the file(If I take out the type I can still upload the file). I was also wondering what the const upload = multer({ dest: 'upload/'}); does because I have a folder(not created by me) that holds weird files that Visual Studio can't support(Notepad can't support it either). I have a strong feeling it's something to do with that line, but like I said, I'm new to Multer. If somebody could come up with a solution that can upload and log the value that would be great!(I have spent a long time writing this I'm trying to get my reputation up so my votes can display to the public; I wouldn't mind if you can upvote my post!!)
Maybe start the URL with a / so that the intended URL is returned instead of its parent or child.
It might solve the folder issue.
and about the "type" middelware, I haven't seen yet any example of upload.any() with passing parameters.
I'm new to Multer too, but I think it might solve the problems
You dont need formidable if you use multer middleware. Multer will parse the input form and populate it in req.body as usual.The file data will be populated in req.files.
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
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'm working with feathers.js on the back-end and React on the front end and I need to implement a way to upload a picture. I'm using multer to handle the upload (and I've tried using busboy as well), but I can't seem to get the actual picture uploaded, or at least access it on req.file.
On the client side I have:
<form method="post" enctype="multipart/form-data" action="/picture/upload">
<input type="file" name="avatar" />
<input type="submit" value="Submit" />
</form>
In /src/middleware/index.js I have:
'use strict';
const uploadPicture = require('./uploadPicture');
const handler = require('feathers-errors/handler');
const notFound = require('./not-found-handler');
const logger = require('./logger');
var multer = require('multer');
const upload = multer({ dest: '../../client/img'});
module.exports = function() {
// Add your custom middleware here. Remember, that
// just like Express the order matters, so error
// handling middleware should go last.
const app = this;
app.post('/picture/upload', upload.single('avatar'), uploadPicture(app));
app.use(notFound());
app.use(logger(app));
app.use(handler());
};
This is src/middleware/uploadPicture.js:
'use strict';
module.exports = function(app) {
return function(req, res, next) {
console.log('req.file', req.file);
console.log('req.body', req.body);
};
};
req.file is always undefined, and req.body does contain the name of the image I uploaded.
I have tried using mutler and busboy on a basic Express project for testing, and it works perfectly, so that makes me think that maybe it has something to do with the middleware feathers.js uses and probably it changes some header or something, so multer can't append the file to the request object.
This is the order in which middleware is defined in src/app.js, which is where the server instance is run:
app.use(compress())
.options('*', cors())
.use(cors())
.use('/', serveStatic( app.get('client') ))
.use(bodyParser.json())
.use(bodyParser.urlencoded({ extended: true }))
.configure(hooks())
.configure(rest())
.configure(services)
.configure(middleware);
Any thoughts on how to handle the image upload in this scenario?
I am using react, so enctype is not a supported HTML attribute. I should have used encType in my form. That fixed the problem.
This question already has an answer here:
Node JS API: Return JSON to user, after service is done.
(1 answer)
Closed 5 years ago.
I'm totally new to node.js, so I'm trying to find a way to create an image-file upload API, which returns a json after the process is finished.
I'm using the Watson Developer Cloud (Visual Recognition), which returns a JSON after finishing the processing task.
I hope you have tips & ideas on how to get this project done. I thought about using the express library?
This is my code, which processes a local image right now and logs the JSON result to the console. I want to be able to upload an image via api and return the JSON, after the process is done.
Thanks a lot!
Code to process Image:
var watson = require('watson-developer-cloud')
var fs = require('fs')
//initialisng the service
var visual_recognition = watson.visual_recognition({
api_key : '<Enter API Key here>',
version: 'v3',
version_date: '2016-05-20'
});
var params = {
images_file: fs.createReadStream('./resources/image.jpg')
};
visual_recognition.classify(params, function(err, res){
if(err)
console.log(err);
else
console.log(JSON.stringify(res, null, 2));
});
First Try for the upload Server (Thanks to #Eduard for the tip):
var express = require('express')
var multer = require('multer')
var upload = multer({ dest: 'uploads/' })
var app = express()
app.post('/upload', upload.single('avatar'), function (req, res, next) {
if(err){
console.log("Error uploading file");
}
console.log(req.file);
console.log(req.body);
res.status(204).end();
console.log("Upload success");
})
app.listen(3000, function () {
console.log('Upload Server listening on port 3000');
});
Unfortunately this returns a 'ReferenceError: err is not defined[..]', while uploading an image with this simple Python Script:
import requests
url='http://localhost:3000/upload'
imageURL = 'ImageURL'
with open(imageURL, 'rb') as image:
filename = image.name
files = {'avatar': (image)}
r = requests.request(method="POST", url=url, files=files)
print(r.text);
print(r.status_code)
Sidenote:
Why do I want to use a Node.js Server?
Unfortunately the Watson-Developer-Cloud Python SDK is not supported on my hardware (a robot) and using the API endpoint with a direct upload from python causes trouble due to the old python Version on the hardware (SNI Problems)
At first, you will need ExpressJS to easily catch the POST, and secondly, you should be using Multer, as it is the easiest to work with when it comes to file uploading in my opinion.
var express = require('express')
var multer = require('multer')
var upload = multer({ dest: 'uploads/' })
var app = express()
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
})
Example taken from Multer repo
You have more info about checking the file itself here: https://github.com/expressjs/multer