Hi I'm new to nodejs and gridFS
I'm trying to display images stored in gridFS to my html page
Currently, I am using this code.
gfs.exist(options, function(err, found){
if(err) return handleError(err);
if(found)
{
console.log("Found Image");
var fs_write_stream = fs.createWriteStream('public/images/'+req.user._id + '_photo' + '.jpg');
var readstream = gfs.createReadStream({
filename: req.user._id + '_photo'
});
readstream.pipe(fs_write_stream);
readstream.on('close', function(){
console.log('file has been written fully');
res.render('profile', {
user : req.user,
message: req.flash('info'),
user_photo_url: 'images/'+req.user._id+'_photo.jpg'
});
});
}
});
But my code need to download image from gridFS. If my server storage is not enough, it should be problematic
Is there any method to display gridFS images to html directly?
Add a route for resources in your images directory and pipe the gridfs readstream to the response directly like so
app.get('/images/:name', function(req, res) {
var readstream = gfs.createReadStream({
filename: req.param('name');
});
res.pipe(readstream);
})
In your html, all you need to do is specify the src url in your images correctly
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))
});
Try the function like below,
function(req,res){
gfs.files.findOne({ filename: req.params.filename }, (err, file) => {
res.contentType(file.contentType);
// Check if image
if (file) {
// Read output to browser
const readstream = gfs.createReadStream(file.filename);
readstream.pipe(res);
} else {
console.log(err);
}
});
};
Related
I'm trying to upload an image to MongoDB, but when I visualize it in mongoCompass it only shows its "_id". So I don't know if it went through or not.
I need to:
Store the image in the DB
Get the image's URL after it's stored there.
I'm using Express, Multer, Body-parser, fs, mongoose
Here's my app.js
const express = require("express"),
app = express(),
bodyParser = require("body-parser"),
fs = require("fs"),
multer = require("multer"),
mongoose = require("mongoose");
mongoose.connect("mongodb://localhost/Images");
app.use(bodyParser.urlencoded(
{ extended:true }
))
app.set("view engine","ejs");
//Schema
var imgSchema = mongoose.Schema({
img:{data:Buffer,contentType: String,nom:String}
});
var image = mongoose.model("image",imgSchema);
// SET STORAGE
var storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, './uploads')
},
filename: function (req, file, cb) {
cb(null, 'uploaded-' + Date.now()+".png")
}
})
var upload = multer({ storage: storage })
app.get("/",(req,res)=>{
res.render("index");
})
app.get("/show",(req,res)=>{
image.find().toArray(function (err,result){
const imgArray = result.map(element =>element._id);
console.log(imgArray);
if(err){
return console.error(err);
}
res.send(imgArray)
})
});
app.post("/uploadphoto",upload.single('myImage'),(req,res)=>{
var img = fs.readFileSync(req.file.path);
var encode_img = img.toString('base64');
var final_img = {
contentType:req.file.mimetype,
image:new Buffer(encode_img,'base64'),
nom:"hi"
};
image.create(final_img,function(err,result){
if(err){
console.log(err);
}else{
console.log(result.img.Buffer);
console.log("Saved To database");
res.contentType(final_img.contentType);
res.send(final_img.image);
}
})
})
//Code to start server
app.listen(2000,function () {
console.log("Server Started at PORT 2000");
})
this is what mongo shows me
This is the image upload folder
Thank you in advance
Everything is here
This Github repo has the answer detailed.
https://github.com/AnasGara/Upload-Image-Express-Mutler
I have been trying to reduce my NextJS bundle size by moving my XLSX parsing to an API route. It uses the npm xlsx (sheetjs) package, and extracts JSON from a selected XLSX.
What I am doing in the frontend is
let res;
let formData = new FormData();
formData.append("file", e.target.files[0]);
try {
res = await axios.post("/api/importExcel", formData);
} catch (e) {
createCriticalError(
"Critical error during file reading from uploaded file!"
);
}
On the API route I am unable to to read the file using XLSX.read()
I believe NextJS uses body-parser on the incoming requests but I am unable to convert the incoming data to an array buffer or any readable format for XLSX.
Do you have any suggestions about how to approach this issue?
I tried multiple solutions, the most viable seemed this, but it still does not work
export default async function handler(req, res) {
console.log(req.body);
let arr;
let file = req.body;
let contentBuffer = await new Response(file).arrayBuffer();
try {
var data = new Uint8Array(contentBuffer);
var workbook = XLSX.read(data, { type: "array" });
var sheet = workbook.Sheets[workbook.SheetNames[0]];
arr = XLSX.utils.sheet_to_json(sheet);
} catch (e) {
console.error("Error while reading the excel file");
console.log({ ...e });
res.status(500).json({ err: e });
}
res.status(200).json(arr);
}
Since you're uploading a file, you should start by disabling the body parser to consume the body as a stream.
I would also recommend using a third-party library like formidable to handle and parse the form data. You'll then be able to read the file using XLSX.read() and convert it to JSON.
import XLSX from "xlsx";
import formidable from "formidable";
// Disable `bodyParser` to consume as stream
export const config = {
api: {
bodyParser: false
}
};
export default async function handler(req, res) {
const form = new formidable.IncomingForm();
try {
// Promisified `form.parse`
const jsonData = await new Promise(function (resolve, reject) {
form.parse(req, async (err, fields, files) => {
if (err) {
reject(err);
return;
}
try {
const workbook = XLSX.readFile(files.file.path);
const sheet = workbook.Sheets[workbook.SheetNames[0]];
const jsonSheet = XLSX.utils.sheet_to_json(sheet);
resolve(jsonSheet);
} catch (err) {
reject(err);
}
});
});
return res.status(200).json(jsonData);
} catch (err) {
console.error("Error while parsing the form", err);
return res.status(500).json({ error: err });
}
}
I successfully coded to upload a image upload into the MongoDB. But now i want to upload multiple images into database. i used gridFS and multer. Can someone help me out to solve this problem
// Create Storage engine
var storage = new GridFsStorage({
url: Mongo,
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',
metadata: {'username': req.body.username}
};
resolve(fileInfo);
});
});
}
});
const upload = multer({ storage });
/*--------------------------------------------------------*/
app.get('/',(req,res)=>{
gfs.files.find().toArray((err,files)=>{
// Check if Files
if(!files || files.length ===0)
{
res.render('index',{files:false});
} else{
files.map(file=>{
if(file.contentType === 'image/jpeg' || file.contentType ===
'image/png')
{
file.isImage = true;
} else {
file.isImage = false;
}
});
res.render('index',{files:files});
}
});
});
/*----------------------------------------------------*/
// Display Image
app.get('/image/:filename', (req,res)=>{
gfs.files.findOne({filename: req.params.filename}, (req,file) =>{
// Check if File
if(!file || file.length ===0)
{
return res.status(404).json({
err: 'No files exist'
});
}
// Check if image
if(file.contentType === 'image/jpeg' || file.contentType === 'image/png')
{
// Read output tp browser
var readstream = gfs.createReadStream(file.filename);
readstream.pipe(res);
}
else
{
res.status(404).json({
err: 'Not an image'
});
}
});
});
i attached code section which is related to image upload. please check this code and give a good trick to upload multiple images to mongoDB
I use mongodb and in mongodb I put my username and password.
The code is:
var mongodb = require('mongodb');
var http = require('http');
var fs=require('fs');
var express = require('express');
var bodyParser = require('body-parser');
var app = express();
app.use(bodyParser());
app.listen(8080, function() {
console.log('Server running at http://127.0.0.1:8080/');
});
app.post('/prova', function(req, res) {
// res.send('You sent the name "' + req.body.username + '".');
var MongoClient = mongodb.MongoClient;
// Connection URL. This is where your mongodb server is running.
var url = 'mongodb://localhost:27017/utente';
MongoClient.connect(url, function (err, db) {
if (err) {
console.log('Unable to connect to the mongoDB server. Error:', err);
} else {
//HURRAY!! We are connected. :)
console.log('Connection established to', url);
var collection = db.collection('login');
// var prova1=({name:"documento1",url:"sadsad",tag:"dc1"});
// do some work here with the database.
var cursor = collection.find();
cursor.each(function (err, doc) {
if (err) {
console.log(err);
} else {
// console.log('Fetched:', doc);
var username=0;
var password=0;
for(valore in doc){
if(valore!="_id"){
if(valore=="username"){
if(doc[valore]==req.body.username){
username=1;
}
}
if(valore=="password"){
if(doc[valore]==req.body.password){
password=1;
}
}
}
}
if(username==1 && password==1){
console.log("entra");
// res.end();
}else{
fs.readFile('C:\\Users\\Eventi\\Desktop\\Node.js\\Progetti\\ProveNodeJS\\NodeJSProve\\paginaRifiuto.html', function (err, html) {
if (err) {
}
res.writeHeader(200, {"Content-Type": "text/html"});
res.write(html);
res.end(html);
});
}
}
});
//Close connection
}
});
});
http.createServer(function(request, response) {
fs.readFile('C:\\Users\\Eventi\\Desktop\\Node.js\\Progetti\\ProveNodeJS\\NodeJSProve\\home.html', function (err, html) {
if (err) {
}
response.writeHeader(200, {"Content-Type": "text/html"});
response.write(html);
response.end();
});
}).listen(8000);
I call first http://localhost:8000 and I put in a text field the wrong value of username and password and after I click login I see my "login fail page" but I obtain this error:
Connection established to mongodb://localhost:27017/utente
_http_outgoing.js:335
throw new Error('Can\'t set headers after they are sent.');
^
Error: Can't set headers after they are sent.
at ServerResponse.OutgoingMessage.setHeader (_http_outgoing.js:335:11)
at ServerResponse.writeHead (_http_server.js:195:21)
at ServerResponse.writeHeader (_http_server.js:233:18)
at C:\Users\Eventi\Desktop\Node.js\Progetti\ProveNodeJS\NodeJSProve\HelloWord.js:67:23
at fs.js:334:14
at FSReqWrap.oncomplete (fs.js:95:15)
//router
app.get('/retrieve_report', function(req, res) {
var retrieved = retrieve_report(req, res);
res.render('retrieve_report.ejs', {
'report' : retrieved
});
});
//Load up the report model
var Report = require('../models/report');
console.log('Report ' + Report.schema);
//expose this function to our app using module.exports
//query
module.exports = function(req, res) {
//console.log('param ' + res.send);
var query = Report.findById(req.param('id'), function(err, doc) {
if(err) {
throw err;
}
else {
console.log('doc ' + JSON.stringify(doc));
res.send(doc);
}
});
}
//app.js
var retrieve_report = require('./config/retrieve_report');//which is the above code
I want to return the document to the router so that I can put its information into my view. I tried "res.json(doc), but that gave me the error, "throw new Error('Can\'t set headers after they are sent.');" Everyone says to use a callback function, but aren't I using a callback function here?
As your error says:
but that gave me the error, "throw new Error('Can\'t set headers after they are sent.');"
Means you are trying to send data the twice.
Sample code:
app.get('/retrieve_report', function(req, res) {
var query = Report.findById(req.param('id'), function(err, doc) {
if(err) {
throw err;
}
else {
console.log('doc ' + JSON.stringify(doc));
res.send(doc);
}
});
This should work..