Downloading file in node using GridFS in production - node.js

I have an express app, which works when I run it locally. The issue is when downloading a file which as saved in mongoDB using GridFS. When running it locally (I just do ./bin/www and go to localhost:3000), I can download the file. But when I run it remotely, I download an html file.
This is the route which handles the response:
router.get('/getfile',function(req,res) {
if (req.isAuthenticated())
{
var gfs = Grid(mongoose.connection, mongoose.mongo);
var id = req.query.id;
gfs.exist({_id: id}, function (err, found) {
if (err) return handleError(err);
if (!found)
res.send('Error on the database looking for the file.')
});
var readStream = gfs.createReadStream({
_id: id
}).pipe(res);
}
else
res.redirect('/login');
});
and that is called by this line in a jade file:
td #[a(href="getfile?id=#{log.videoId}" download="video") #[span(name='video').glyphicon.glyphicon-download]]
On the server, I'm doing:
/logApp$ export NODE_ENV=production
/logApp$ ./bin/www
the mongoDB deamon is running. In fact, I can query the database. And I'm not writing any file! I want to read it.
EDIT: I found the error message:
MongoError: file with id #### not opened for writing

You need to move the code that pipes the file to the response into the gfs.exist callback so that it runs after the exist check.
gfs.exist({ _id: id }, function(err, found) {
if (err) {
handleError(err);
return;
}
if (!found) {
res.send('Error on the database looking for the file.')
return;
}
// We only get here if the file actually exists, so pipe it to the response
gfs.createReadStream({ _id: id }).pipe(res);
});
Apparently you get that generic "not opened for writing" error if the file doesn't exist.

Related

How do I read a file in NodeJS whose URL is stored in my database?

When I try to read a file that is stored in the database, node gives me an error saying:
"error": "ENOENT: no such file or directory, open 'http://localhost:8000/assets/uploadNk2i8BAE81Wp6pFI6TtF-.pdf'"
But, when I visit that link in the browser, I can see the pdf file. So, why is node failing to read the file?
This is my code:
fs.readFileSync(req.user.resume, 'utf-8', (err,data) => {
if(err) {
res.send(err);
}
else {
res.send(data);
}
})

Node.Js wont Upload file to Directory

I want to simulate an upload in Node.js REST api.
I want to make the REST api upload the files to a directory and then save the URL of the saved file to the database table.
For some reason, I dont know of , he just tells me , "No Files uploaded" But looking thru, everything seems okay.
I am testing thru Postman, so thats where i seem to be getting the output and what it tells me.
My code is looking like this:
app.post('/api/createpost', function (req,res){
if(!req.files) return res.status(400).send('No Files uploaded');
const {foo} = req.files;
const uploadTo = `postimages/${foo.name}`;
foo.mv(uploadTo, (err) =>{
if(err) return res.status(500).send(err);
//push data to mysql Db
var username = req.body.username;
var imgUrl = 'http://localhost/'+uploadTo;
var post = req.body.post;
dbConn.query('INSERT INTO instagramclonedbposts SET ?', [username, imgUrl, post], function(error, results, fields){
if(error) throw error;
return res.send({error:false, message: 'Post Created'});
});
});
});
Testing in Postman, I have this :
Could there be something i am missing?

Formidable using "end" event with file upload

I am using Formidable with Express in nodeJS in an attempt to have a simple single file upload scheme. I have confirmed that a file is actually sent over from the client-side, but where it seems to run into troubles is on the server-side.
index.js
app.post('/', (req, res) => {
const form = formidale();
form.on('file', (filename, file) => {
fs.rename(file.path, `./data/nodes.csv`, err => {
if (err) {
console.log(`There was an error in downloading a CSV file: ${err}`);
return null;
}
else {
console.log("CSV file has been uploaded correctly.");
}
});
});
form.on('error', err => {
console.log(`There was an error in downloading a CSV file: ${err}`);
return null;
});
form.on('end', () => {
console.log(fs.readFileSync('./data/nodes.csv')); // test to see if file exists
const nodes = assignMetrics();
console.log(nodes);
return nodes;
});
form.parse(req);
});
}
The main trouble I seem to find is that the form.on('end', ...) event does not seem to wait till the file has finished uploading to fire. I have confirmed this by trying to read the file in the event, but by that point it doesn't exist? The documentation though appears to suggest it is only meant to fire "after all files have been flushed [from the APIs pipe it infers]".
There appears to be no other events available that might wait till the file has been uploaded to be called? I also don't want to start throwing in layers of promises and such unless it is the only option, as each new layer of promises I find is a chance for unintended effects to happen.

request body characters showing ? using fetch or request from quickbooks

I am using quickbooks api in a node 10.16 environment.
I am trying to get the PDF through the API.
I am getting what looks like the correct response but when I open it it shows blank
I have downloaded a file using postman directly and that file works.
I have opened both files up using notepad++ and I can see some characters on my file have ? or a square where on the postman file I see a character.
This google folder has both files
This is the main code where I grab the information from the API using fetch
return fetch(url, fetchOptions).then((response) => {
if (response.ok) {
return response.text()
}
response.text() is where the bad decoding is happening because I have saved it directly to a file or tried decoding it with TextDecoder and it always gives me bad characters.
Here is what I have tested so far
return response.arrayBuffer().then(buffer => {
let decodedValue = new util.TextDecoder('utf-8').decode(buffer)
fs.writeFile('decodetest.pdf', decodedValue, (err) => {
// throws an error, you could also catch it here
if (err) throw err;
// success case, the file was saved
console.log('decode file saved!');
});
return decodedValue;
});
rp below is using a different package response-promise. Also giving the same results.
return rp(options)
.then(function (response) {
console.log("Did a new response");
response.body
fs.writeFile('requesttest.pdf', response.body, (err) => {
// throws an error, you could also catch it here
if (err) throw err;
// success case, the file was saved
console.log('request test file saved!');
});
})
.catch(function (err) {
// Delete failed...
});

Send file back after GET request Node.js

I am trying to build a REST API using a MEAN stack and I have encountered a problem. I am saving a .txt file sent in a POST request to the server and saving it using multer in an /uploads folder. I am then saving the req.file information in a collection on mongodb (path included).
The problem that I have now is that I want to be able to handle a GET request for that specific file with the ObjectId. However I want to be able to get the file from the file path and then send it to the user making the GET request.
Right now I am only returning the information corresponding to the ObjectId passed, not the file. How can I send back the whole .txt file back to the user?
exports.findById = function(req, res) {
try
{
var id = new require('mongodb').ObjectID(req.params.id);
console.log('Retrieving log: ' + id);
db.collection('logs', function(err, collection) {
if(err)
{
console.log(err);
}
else
{
collection.findOne({'_id':id}, function(err, item) {
if (err) {
console.log('Error finding log: ' + err);
res.send({'error':'An error has occurred'});
} else {
console.log('' + item + ' found log');
console.log(item.path);
var file = __dirname + item.path;
res.download(file);
//res.send(item);
}
});
}
});
}
catch (e)
{
console.log('Id passed not correct');
res.send({'error':'Id passed not correct'});
}
};
At the end I finally got the server to respond to the GET request.
I had to find the file path of the file that had been saved into the database.
collection.findOne({'_id':id}, function(err, item) {
if (err)
{
console.log('Error finding log: ' + err);
res.send({'error':'An error has occurred'});
}
if (item)
{
//Create the path of the file wanted
filepath = path.join(__dirname, "../uploads", path.normalize(item.filename));
//Send file with the joined file path
res.sendFile(filepath);
}
else
{
console.log("Could not find entry");
res.send({'error':'No match found'});
}
});
This enabled me to send the file back by getting the full path of the file.

Resources