Cannot read "path" property of undefined Nodejs - javascript

Here is my jade file
form(method="post", action="/upload", enctype="multipart/form-data")
input(type="file", name="logName")
button(type="submit") Upload
And my index.js file
/* GET home page. */
router.get('/', function (req, res) {
res.render('fileUpload', { title: 'Building a Log File Viewer' });
});
var formidable = require('formidable'),
fs = require('fs'),
util = require('util');
/* POST the file upload */
router.post('/upload', function (req, res) {
var form = new formidable.IncomingForm();
form.parse(req, function (err, fields, files) {
fs.readFileSync(files.upload.path, function (err, data) {
if (err) throw err;
console.log("Test");
})
});
});
I keep getting the TypeError property that property "path" is undefined; however, when I sumbit the code under a http.createServer, instead of a router.post, it works fine. I have also tried the asychronous file reading, and it gave me the same error. Any ideas?

please try
fs.readFileSync(files.logName.path, function (err, data){ ... });
instead of
fs.readFileSync(files.upload.path, function (err, data) { ... });

Related

Passing a pdf file to a function when it requires a path or link

I am working on a web application for an online library. I want to extract metadata from the PDF's that will be uploaded and for that I am using the nodejs library pdf.js-extract and multer-gridfs-storage for the upload. The problem is that I am receiving a PDF file (req.file) and the function requires a path or link to the PDF file and therefore shows the error
"TypeError [ERR_INVALID_ARG_TYPE]: The "path" argument must be one of type string, Buffer, or URL. Received type object"
I would like to know if there is a way to pass a file as a link, save the file locally temporarily or find another library that fits my needs.
This is my current code.
const PDFExtract = require('pdf.js-extract').PDFExtract;
app.post('/upload', upload.single('file'), (req, res) => {
const pdfExtract = new PDFExtract();
const options = {};
pdfExtract.extract(req.file, options, (err, data) => {
if (err){
res.status(404).send({ message: err });
}
res.status(200).send({ message: data });
});
});
(Edit for clarification) I am using multer with gridFS to upload a file to mongoose.
const multer = require('multer');
const GridFsStorage = require('multer-gridfs-storage');
// 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 });
Solution inspired by Oliver Nybo
app.post('/upload', upload.single('file'), (req, res) => {
const pdfExtract = new PDFExtract();
const options = {};
var readableStream = gfs.createReadStream({ filename : req.file.filename });
var buff;
var bufferArray = [];
readableStream.on('data',function(chunk){
bufferArray.push(chunk);
});
readableStream.on('end',function(){
var buffer = Buffer.concat(bufferArray);
buff=buffer;
pdfExtract.extractBuffer(buff, options, (err, data) => {
if (err) {
res.status(404).send({ message: err });
}
res.status(200).send({ message: data });
});
})
});
According to multer's api documentation, you can use req.file.path to get the full path of the uploaded file.
const PDFExtract = require('pdf.js-extract').PDFExtract;
app.post('/upload', upload.single('file'), (req, res) => {
const pdfExtract = new PDFExtract();
const options = {};
pdfExtract.extract(req.file.path, options, (err, data) => {
if (err){
res.status(404).send({ message: err });
}
res.status(200).send({ message: data });
});
});
Edit: I just read the multer options and there is an option called preservePath.
preservePath - Keep the full path of files instead of just the base name
Edit 2: I think you need to extract the file from the database with gridfs-stream, then convert it into a buffer (like in this thread), and then use PDFExtract's extractBuffer function.

My code is deleting the file and removing it from the database records, however, I get an error in the console

I'm trying to add a delete image functionality to my website and even though my code deletes the file from the images folder and removes the image record from my database, I get an error in the console and I don't get redirected to my home page. The error is :
DeprecationWarning: Calling an asynchronous function without callback is deprecated.
And my code:
var express = require('express');
var router = express.Router();
var db = require('../helpers/db');
var fs = require('fs');
router.post('/', function(req, res, next) {
if (req.method == 'POST') {
var id = req.body.id;
var path = req.body.path;
var author = req.body.author;
var completePath = 'public/images/uploads/' + path;
db.query('DELETE FROM image WHERE id = ?', [id], function(error, results, fields) {
if (error) throw error;
if (fs.unlink(completePath)) {
console.log('Successful');
res.redirect('/');
} else {
console.log('Unsuccessful');
}
})
}
});
module.exports = router;
My console logs Unsuccessful and it doesn't redirect me to res.redirect('/');
fs.unlink is an asynchronous function that takes a callback on success. You should use it like this:
db.query('DELETE FROM image WHERE id = ?', [id], function(error, results, fields) {
if (error) throw error;
fs.unlink(completePath,function(err) {
if(err) {
console.log('unsuccessful');
return;
}
console.log('successful');
res.redirect('/');
});
})

express.js multiple file upload callback

I'm new to node.js & express.js, so... I want to upload multiple files, and later work with them.
But i need to send a response (ok or error status) after all my files have been saved on disk, or if one failed - then send an error callback.
Now I have such code:
var express = require('express');
var router = express.Router();
var multipart = require('connect-multiparty');
var multipartMiddleware = multipart();
var fs = require('fs');
router.post('/upload', multipartMiddleware, function(req, res) {
var reqBody = req.body;
var reqFiles = req.files;
saveFile(reqFiles, 'main.xlsx', function(err) {
if (err) {
res.status(404).send('');
return;
}
res.send('Multi-File File uploaded');
}
});
function saveFile(file, name, callback) {
fs.writeFile('./uploads/' + name, file, callback);
}
but how can i change my code to parse this:
router.post('/upload', multipartMiddleware, function(req, res) {
var reqBody = req.body;
var reqFiles = req.files;
saveFile(reqFiles['files'][0], 'main.xlsx', function(err) {
if (err) {
res.status(404).send('');
return;
}
}
saveFile(reqFiles['files'][1], 'second.xlsx', function(err) {
if (err) {
res.status(404).send('');
return;
}
}
res.send(''); // only after first two fileUploaders have finished
});
function saveFile(file, name, callback) {
fs.writeFile('./uploads/' + name, file, callback);
}
You need to iterate through req.files. You can use async library.
For example:
async.each(req.files, function(file, callback) {
saveFile(file, file.name, callback)
}, function(err) {
res.send('')
})
The module recommends not using this. Use the multiparty module directly.
When you have the list of files they will also have file names. you can loop through those and save each file asynchronously. Then respond. Take a peek here

Mongoose: .save is not a function

I'm very new and I've looked through the archives but just what's going on in this code eludes me. I used express-generator to create a calendar app and now I want to hook it up to MongoDB. The actual connection to Mongo is working, but I can't get it to save a document.
The relevant portion of my global.js (where I'm running my front-end Javascript) looks like this:
$(document).ready(function() {
var ev = new Event({ date: "a6_13_2016", time: 900, description:"Fencing"});
ev.save(function(err) {
if (err) console.log(err);
else console.log("Success!")
})
This is where I'm getting the "TypeError: ev.save is not a function" message. My models/Events.js looks like this:
var mongoose = require('mongoose');
var eventSchema = new mongoose.Schema({
date: String,
time: Number,
description: String
});
module.exports = mongoose.model('Event', eventSchema);
My routes/events.js looks like this:
var express = require('express');
var router = express.Router();
var mongoose = require('mongoose');
var Event = require('../models/Events.js');
/* GET /event listing. */
router.get('/', function(req, res, next) {
Event.find(function (err, dates) {
if (err) return next(err);
res.json(dates);
});
});
/*POST event*/
router.post('/', function(req, res, next) {
Event.create(req.body, function (err, post) {
if (err) return next(err);
res.json(post);
});
});
/* GET /event/id */
router.get('/:id', function(req, res, next) {
Event.findById(req.params.id, function (err, post) {
if (err) return next(err);
res.json(post);
});
});
module.exports = router;
I want to save something to test it, but it's giving me ".save is not a function. Other than
var events = require('./routes/events');
app.use('/events', events);
and the code establishing the Mongoose connection my app.js file is boilerplate. What do you think is the problem?
I see
$(document).ready(function() {
Are you trying to use Mongoose in browser?
It's supposed to be used on the server-side.
In browser you need to send AJAX request to the server:
$('#save').click(function() {
$.post('/event', function(response) { console.log(reposne) })
});
On the server you should add a route that will handle your AJAX request, and inside this route you can save your model:
router.post('/event', function(req, res) {
var ev = new Event({ date: "a6_13_2016", time: 900, description:"Fencing"});
ev.save(function(err) {
if (err) console.log(err);
else console.log("Success!")
})
});
Please note that you don't need the 3rd param next in your rotues. It is used only in middlewares
Are you sure that line
var Event = require('../models/Events.js');
has the correct path?
You are creating an ev object from Event function and it seems that ev is undefined, judging from the error description.
If your Event file is not properly loaded you will not have access to .save function.

MongoDB and Express: Type Error: Converting Circular structure to JSON

I am new to MEAN stack. I am trying to retreive a list of documents from MongoDB. I have used Visual Studio 2013 community edition to create a basic Nodejs Express application. Visual studio created app.js file on the root for configuration. I have put following code in app.js which is relevant to mongodb:
var mongo = require('myDB');
var db = new mongo.Db("myDB", new mongo.Server("localhost", "27017"),
{ safe: true }, { auto_reconnect: true });
// Make our db accessible to our router
app.use(function (req, res, next) {
req.db = db;
next();
});
In the routes folder that visual studio created, I have created a js file which will perform CRUD operations. I have following code in this file:
var express = require('express');
var router = express.Router();
router.get('/myRecords', function (req, res) {
var db = req.db;
db.open(function (err, db) {
if (err)
console.log(err);
else {
var collection = db.collection('myCollection');
var dataToSend = collection.find();
res.send(dataToSend);
}
})
});
module.exports = router;
I am Type Error: Converting Circular structure to JSON.
I am trying to not using any schema.
Please advice.
For those of you, who encounter the similar problem, find() doesn't return the document, we need to use toArray to retrieve documents. Following code did the trick:
router.get('/myRecords', function (req, res) {
var db = req.db;
db.open(function (err, db) { // <------everything wrapped inside this function
db.collection('myCollection', function (err, collection) {
collection.find().toArray(function (err, items) {
res.send(items);
db.close();
});
});
});
});

Categories