GET images from GridFs to Angular - javascript

I´m storing images from my angular app in MongoDB using GridFs. But i cant figure out, how to GET the images out of the DB to the app?
I´m using a custom objectId for the query.
EDIT
It looks like the GET part now works, but then there was no media in the collection. I played a bit with the code, and now I can see fs.chunks and fs.files in the database. I think the problem is, that I try to query for metadata in the GET request. This returns no response data. Anybody got an idea how to fix this?
var fs = require('fs');
var conn = mongoose.connection;
var Grid = require ('gridfs-stream');
Grid.mongo = mongoose.mongo;
var gfs = Grid (conn.db);
var buffer = "";
app.post('/uploads/', multer({
upload: null,
onFileUploadStart: function (file, req){
this.upload = gfs.createWriteStream({
filename: file.originalname,
metadata:{"objectId" : req.body.project_id},
mode: "w",
chunkSize: 1024*4,
content_type: file.mimetype,
root: "fs",
});
},
onFileUploadData: function(file, data) {
this.upload.write(data);
},
onFileUploadComplete: function(file, res) {
done=true;
}
}), function(req, res){
res.status(200);
res.send("Success!");
});
app.route('/uploads/media/:projectId').get(function (req, res){
var readstream = gfs.createReadStream({
"metadata.objectId" : req.params.projectId
});
res.set('Content-Type', 'image/jpeg');
readstream.pipe(res);
});

You need to write the stream back out to your response. Here is another similar question. But basically you either need to pipe the stream to your response, or use the stream's end event and write the result to your response. The following code pipes to the response and sets a content-type of image/jpeg.
app.get('/uploads/:objectId', function(req, res){
var options = {
_id : req.params.objectId
};
gfs.exist(options, function(err, exists) {
if(!exists) {
res.status(404);
res.end();
} else {
var readstream = gfs.createReadStream(options);
res.set('Content-Type', 'image/jpeg');
readstream.pipe(res);
}
});
});

var pi_id = fields.pic_id;
gfs.findOne({ _id: pi_id }, function (err, file) {
console.log(file);
if (err) return res.status(400).send(err);
if (!file) return res.status(404).send('');
res.set('Content-Type', file.contentType);
res.set('Content-Disposition', 'attachment; filename="' + file.filename + '"');
var readstream = gfs.createReadStream({
_id: file._id
});
readstream.on("error", function(err) {
console.log("Got error while processing stream " + err.message);
res.end();
});
readstream.pipe(res);
console.log(readstream.pipe(res))
});

Related

How to read a csv file from azure blob storage using NodeJS?

I have uploaded a csv file in to azure blob storage. Now I want to retrieve the file from azure blob storage, I have used the following code. After receiving the csv file I will convert in to json and do some manipulation.
var blob = require('../../service/blobstorage');
var chkFile = async function (req,res) {
let reqq = {
storageName:"consent",
blobFileName: "filename",
downloadFileName:"filenamee"
}
let storeBlb = await blob.getBlobDataToStreamm(reqq,res)
}
In blobstorage file,
const getBlobDataToStreamm= async function(req, res){
try{
var fs = require('fs');
const storageName= req.storageName;
const blobFileName= req.blobFileName;
const downloadFileName= req.downloadFileName;
res.setHeader("Content-Disposition", "attachment;filename=" + downloadFileName);
res.setHeader("Content-Type", "text/csv");
res.setHeader("Access-Control-Allow-Headers","X-Requested-With,content-type");
blobService.getBlobToStream(storageName, blobFileName , res, function(error, result, response) {
if(error){
console.log('error',error);
res.send({error:error, status: false});
}
else{
console.log('resp',result);
res.end();
}
})
}catch(err){
console.log("err ",err);
res.send({error:err, status: false});
}
}
chkFile();
But I'm getting the error
err TypeError: Cannot read property 'setHeader' of undefined

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.

Image upload isn't working using multer

I setup multer like this
let multer = require('multer');
let apiRoutes = express.Router();
let UPLOAD_PATH = '../uploads';
let storage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, UPLOAD_PATH);
},
filename: (req, file, cb) => {
cb(null, file.fieldname + '-' + Date.now());
}
});
let upload = multer({ storage: storage });
and in route I am getting data and an image and use multer like!
apiRoutes.post('/update', passport.authenticate('jwt', { session: false }), (request, response) => {
let record = {
name: request.body.name,
location: request.body.location,
about: request.body.about,
userid: request.body.userid,
avatar: request.body.filename
};
let userData = {
name: request.body.name
};
if (request.body.filename) {
upload(request, response, (error) => {
});
}
profile.findOneAndUpdate({ userid: request.body.userid }, record, {new: true}, (error, doc) => {
if (error) response.json(error);
user.findOneAndUpdate({ _id: request.body.userid }, record, (error, result) => {
if (error) throw error;
response.json(doc);
});
});
});
What is happening with this code is that when I do not send an image to backend then I get data from front end and store it into database. But when I send image along side data then it return POST /api/1.0/profile/update 401 0.396 ms - -.
It means I am not getting any data at all. Whats wring with the code here?
You can't use Multer in your /update route. Use Multer in your router like this:
var upload = multer({ dest: 'uploads/' })
apiRoutes.post('/profile', upload.single('image'), function (req, res, next) {
// Uploaaded
})
if you add it and still can't get our file, you should update your form with this parameter: enctype="multipart/form-data"

Simple Node.JS REST API call

I have a simple app that requires a REST API call to perform CRUD (Create,Read,Update,Delete). However, i can't seem to get the REST API working.
When it's executing the put operation, i'm getting
"api.js:81 Uncaught (in promise) SyntaxError: Unexpected end of JSON input
at callAPI (api.js:81)"
I'm using Api.js to check the API calls.
api-photos.js
//photos.js
var express = require('express');
var router = express.Router();
var multer = require('multer');
var photoController = require('../../controllers/photoController');
var upload = multer({
storage: photoController.storage,
fileFilter: photoController.imageFilter
});
//import PhotoService
const PhotoService = photoController.PhotoService;
router.use((req, res, next)=>{
//set mime type for all request and origin
res.set({
'Access-Control-Allow-Origin':'*',
'Access-Control-Allow-Methods':'GET,PUT,POST,DELETE,OPTIONS',
"Access-Control-Allow-Headers":"Content-Type, Access-Control-Allow-Headers",
'Content-type':'applicaion/json'
});
if(req.method == 'OPTIONS'){
return res.status(200).end();
}
next();
})
// photos - list
router.get('/', (req, res, next)=>{
PhotoService.list()
//returns promise - argument passed photos
.then((photos)=>{
console.log(`API: Found images: ${photos}`);
res.status(200);
//set content type header to application/json - set correct mime type
res.send(JSON.stringify(photos));
});
})
// photos/:photoid - find
router.get('/:photoid', (req, res, next)=>{
PhotoService.read(req.params.photoid)
//returns promise - argument passed photos
.then((photo)=>{
console.log(`API: Found images: ${photo}`);
res.status(200);
//set content type header to application/json - set correct mime type
res.send(JSON.stringify(photo));
}).catch((err)=>{
});
});
// /photos POST create
router.post('/', upload.single('image'), async (req, res, next)=>{
var path = "/static/img/" + req.file.filename;
var photo = {
originalname: req.file.originalname,
mimetype: req.file.mimetype,
imageurl: path,
title: req.body.title,
filename: req.file.filename,
description: req.body.description,
size: req.file.size / 1024 | 0
}
//calling on photo service to return json object
try{
const photoSave = await PhotoService.create(photo);
res.status(201);
res.send(JSON.stringify(photoSave));
}catch(err){
console.log(err);
throw new Error("PhotoSaveError", photo);
}
});
// /photos/photoid: PUT - update
router.put('/:photoid', (req, res, next)=>{
console.log(`putting ${req.params.photoid}`);
let putdata = req.body;
PhotoService.update(req.params.photoid, putdata)
console.log()
.then((updatePhoto)=>{
res.status(200);
res.send(JSON.stringify(updatedPhoto));
}).catch((err)=> {
res.status(404);
res.end();
});
});
// /photos/photoid: DELETE - delete
router.delete('/:photoid', (req, res, next)=>{
PhotoService.delete(req.params.photoid)
.then((photo) => {
console.log(`Found images: $(photo)`);
res.status(200);
res.send(JSON.stringify(photo));
}).catch((err)=> {
res.status(404);
res.end();
});;
});
module.exports = router;
photo.js
//photos.js
var express = require('express');
var router = express.Router();
var app = express();
var multer = require('multer');
var photoController = require('../controllers/photoController');
var flash = require('express-flash');
//create upload object- intialize
var upload = multer({
storage: photoController.storage,
fileFilter: photoController.imageFilter
});
//Photo model import is required
var Photo = require('../models/photoModel');
const PhotoService = photoController.PhotoService
//flash messaging
router.use(flash());
//LIST - Get request to search database for our photos
router.get('/', (req, res, next)=>{
//search the DB for the photos
PhotoService.list()
.then((photos)=>{
//call photos view
res.render('photos', {
photos : photos,
flashMsg: req.flash("fileUploadError")
});
})
.catch((err)=>{
if (err) {
res.end("ERROR!");
}
});
});
//FIND - route for getting photo Details with form for editing
router.get('/:photoid', (req, res, next)=>{
console.log("finding "+req.params.photoid);
PhotoService.read({'_id': req.params.photoid})
//return promoise then handle it to render photo
.then((photo)=>{
res.render('updatePhoto', {
photo: photo,
flashMsg: req.flash("photoFindError")
});
}).catch((err)=>{
if (err) console.log(err);
});
});
//DELETE - route for deleting the photos
router.delete('/delete/:photoid', function(req, res){
PhotoService.delete({'_id': req.params.photoid})
.then((photos) => {
res.redirect('/photos');
});
});
//UPDATE - route for posting newly updated details
router.post('/:photoid', (req, res, next)=>{
PhotoService.update({'_id': req.params.photoid})
//return promoise then set photo data details
.then((photo)=>{
var data = {
title: req.body.title,
description: req.body.description
}
//set the data, save the photo details and redirect to photo list
photo.set(data);
photo.save().then(()=>{
res.redirect('/photos');
});
})
.catch((err)=>{
if (err) console.log(err);
});
});
//CREATE - post fields to the server and save them
router.post('/', upload.single('image'), (req, res, next)=>{
var path = "/static/img/" + req.file.filename;
var photo = {
originalname: req.file.originalname,
mimetype: req.file.mimetype,
imageurl: path,
title: req.body.title,
filename: req.file.filename,
description: req.body.description,
size: req.file.size / 1024 | 0
}
//Saving photo to DB
var photo = new Photo(photo);
photo.save()
.then(()=>{
//redirect after save, if succesfull
res.redirect('/photos');
})
//Catch error logs error
.catch((err)=>{
if (err){
console.log(err);
throw new Error("PhotoSaveError", photo);
}
});
});
//function will get called if above gets unhandled error - flash to display image and redirect
router.use(function(err, req, res, next){
console.error(err.stack);
if (err.message == "OnlyImageFilesAllowed"){
req.flash('fileUploadError', "Please select an image file with jpg, png, or gif")
res.redirect('/photos');
//2nd condition error if there was a problem saving
} else if (err.message == "PhotoSaveError"){
req.flash('photoSaveError', "There was a problem saving the photo")
res.redirect('/photos');
} else{
next(err);
}
});
//export the module
module.exports = router;
api.js
// wrap in IIFE to control scope
(function(){
const baseURL = 'http://localhost:8080';
function testAPIs(){
// test list first
var testId = '';
var testJSON = {};
// list
callAPI('GET', '/api/photos', null, null)
.then((list)=>{
console.log('\n\n***************************\nlist results:');
console.log(list);
testId = list[0]._id;
// create
let input = document.querySelector('input[type="file"]')
let data = new FormData()
data.append('image', input.files[0]);
data.append('title', 'My API Test Title');
data.append('description','This is an AJAX API test');
callAPI('POST', '/api/photos', null, data)
.then((photo)=>{
photoId = photo._id;
savedPhoto = photo; // keep a handle to the created photo object
console.log('\n\n***************************\ncreate results:');
console.log(photo);
// find
callAPI('GET','/api/photos/'+photoId, null, null)
.then((photo)=>{
console.log('\n\n***************************\nfind results:');
console.log(photo);
// update
testJSON.description += ' appended by the AJAX API ';
callAPI('PUT','/api/photos/'+photoId, null, savedPhoto)
.then((photo)=>{
console.log('\n\n***************************\nupdate results:');
console.log(photo);
//delete
callAPI('DELETE', '/api/photos/'+photoId, null, null)
.then((result)=>{
console.log('\n\n***************************\ndelete result:');
console.log(result);
})
});
});
});
})
.catch((err)=>{
console.error(err);
});
}
async function callAPI(method, uri, params, body){
jsonMimeType = {
'Content-type':'application/json'
}
try{
/* Set up our fetch.
* 'body' to be included only when method is POST
* If 'PUT', we need to be sure the mimetype is set to json
* (so bodyparser.json() will deal with it) and the body
* will need to be stringified.
* '...' syntax is the ES6 spread operator.
* It assigns new properties to an object, and in this case
* lets us use a conditional to create, or not create, a property
* on the object. (an empty 'body' property will cause an error
* on a GET request!)
*/
var response = await fetch(baseURL + uri, {
method: method, // GET, POST, PUT, DELETE, etc.
...(method=='POST' ? {body: body} : {}),
...(method=='PUT' ? {headers: jsonMimeType, body:JSON.stringify(body)} : {})
});
return response.json(); // parses response to JSON
}catch(err){
console.error(err);
return "{'status':'error'}";
}
}
// Calls our test function when we click the button
// afer validating that there's a file selected.
document.querySelector('#testme').addEventListener("click", ()=>{
let input = document.querySelector('input[type="file"]')
if (input.value){
testAPIs();
}else{
alert("please select an image file first");
}
});
})();
Here is an update PUT handler which should stop throwing "undefined .then of ...", note that updatePhoto needed to be renamed to updatedPhoto as well.
router.put('/:photoid', (req, res, next) => {
console.log(`putting ${req.params.photoid}`);
let putdata = req.body;
PhotoService.update(req.params.photoid, putdata).then((updatedPhoto) => {
res.status(200);
res.send(JSON.stringify(updatedPhoto));
}).catch((err) => {
res.status(404);
res.end();
});
});
And if you are using node 8+ you can use async/await. It simplifies the code and makes the problems easier to see:
router.put('/:photoid', async (req, res, next) => {
try {
console.log(`putting ${req.params.photoid}`);
let putdata = req.body;
const updatedPhoto = await PhotoService.update(req.params.photoid, putdata);
res.status(200);
res.send(JSON.stringify(updatedPhoto));
} catch (e) {
res.status(404);
res.end();
}
});

Don't find file when i upload image to server nodejs (use multer)

I have some problems with my server nodejs when i upload a image by multer.
https://github.com/expressjs/multer
When i go to folder uploads, i don't see my file uploaded!
My code:
app.use(multer(
{
dest: path.join(__dirname, 'uploads'),
inMemory: true,
includeEmptyFields: true,
onFileUploadStart: function (file, req, res) {
console.log('onFileUploadStart');
console.log(file);
},
onFileUploadData: function (file, data, req, res) {
console.log('onFileUploadData');
console.log(file);
},
onFileUploadComplete: function (file, req, res) {
console.log('onFileUploadComplete');
console.log(file);
},
limits: {
fieldNameSize: 999999999,
fieldSize: 999999999
},
onParseStart: function() {
console.log('Starting to parse request!');
},
onParseEnd: function(req, next) {
console.log('Done parsing!');
next();
},
onError: function(e, next) {
if (e) {
console.log(e.stack);
}
next();
}
}));
And route: (I received file from client)
router.post('/newapi/addimages',function(req,res){
try{
// fileName = file.name, file name passed by client. Not used here. We use the name auto-generated by Node
var file = req.files.file;
var filePath = file.path;
var lastIndex = filePath.lastIndexOf("/");
var tmpFileName = filePath.substr(lastIndex + 1);
var image = req.body;
image.fileName = tmpFileName;
return res.send({ok:'heyyou'});
}
catch(err){
console.log(err);
return res.send({ok:'heyyou'});
}
});
My result:
It's because you have the inMemory option set to true. This option makes the image stay in the process memory instead of piping it to the filesystem and is accessible through the req.files.file.buffer.
Change inMemory to false and you'll be good to go.
You don't have to set each option, and for your application you'd be good with most default values.
app.use(multer({ dest: path.join(__dirname, 'uploads') }));

Categories