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
Related
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 am using ionic 5 & capacitor.
For some reason, the readAsDataURL isnt working and it isnt showing me an error message either.
the path & file name seem fine, they are :
filePath: file:///storage/emulated/0/Android/data/io.ionic.starter/cache/1763816379-cropped.jpg
path : file:///storage/emulated/0/Android/data/io.ionic.starter/cache/
fileName: 1763816379-cropped.jpg
showCroppedImage(ImagePath) {
var filePath = ImagePath;
let fileName = filePath.split("/").pop();
let path = filePath.substring(0, filePath.lastIndexOf("/") + 1);
alert(filePath);
alert(fileName);
alert(path);
alert("works till here");
this.file
.readAsDataURL(path, fileName)
.then((base64) => {
alert(base64);
})
.catch((err) => {
console.log(err);
alert(err);
});
}
this.file.createFile(
this.file.externalDataDirectory,
"base64string.txt",
true
);
this.file.readAsText(this.file.externalDataDirectory, "base64string.txt");
this.blob = new Blob([this.base64string]);
this.file
.writeFile(
this.file.externalDataDirectory,
"base64string.txt",
this.blob,
{ replace: true, append: false }
)
.then(() => {
alert("File saved in internal storage/android/data/io.starter.ionic/");
});
}
Earlier, my file was getting saved in an internal directory which was not accessible by a user. So i used the externalDataDirectory function, which fixed my issue. It stores the file in an external directory which is accessible by the user.
The file is stored in "internal storage/android/data/#app_id#/"
I ended up sorting the problem for my application and I have included it below:
/** #desc crop the selected image */
async cropImage(fileUrl: any) {
this.show_spinner = true;
await this.ionLoader.showLoader('Cropping Image...');
this.crop.crop(fileUrl, {
quality: 75,
targetHeight: 320,
targetWidth: 240
})
.then(
async (newImage) => {
this.show_spinner = false;
await this.ionLoader.hideLoader();
this.showCroppedImage(newImage.split('?')[0]);
},
async (error: IonicResultMessageInterface) => {
this.show_spinner = false;
await this.ionLoader.hideLoader();
console.error('Error cropping image', error);
console.log(error);
this.setUserProfileImage();
this.toasterService.showToast(error.message, 'failure');
}
);
}
/** #desc show the image after it has been cropped */
async showCroppedImage(ImagePath: string) {
console.log(ImagePath);
this.show_spinner = true;
const copyPath = ImagePath;
const splitPath = copyPath.split('/');
const imageName = splitPath[splitPath.length - 1];
const file_ext = imageName.substr(imageName.lastIndexOf('.') + 1);
try {
const base64 = await Filesystem.readFile({ path: ImagePath});
if (base64) {
console.log(base64);
this.userImageUrl = 'data:image/' + file_ext + ';base64,' + base64.data;
this.show_spinner = false;
await this.updateProfilePictureMethod();
} else {
this.show_spinner = false;
console.log('Error in the showCroppedImage File method');
console.log('Unexpected Error');
this.setUserProfileImage();
this.toasterService.showToast('Unexpected Error Occurred in the showCroppedImage File', 'failure');
}
} catch (error) {
this.show_spinner = false;
console.log('Error in the showCroppedImage File method');
console.log('Unexpected Error');
this.setUserProfileImage();
this.toasterService.showToast(error.message, 'failure');
}
}
I am trying to upload an image to Firebase Storage, however, ref.putfile() leads to the error in the tittle
I didn't find any appropriate resource related to this error
This is where I get image from user:
openPicker = () => {
// More info on all the options is below in the API Reference... just some common use cases shown here
const options = {
title: 'Fotoğraf Seç',
storageOptions: {
skipBackup: true,
path: 'images',
},
};
ImagePicker.showImagePicker(options, (response) => {
console.log('Response = ', response);
if (response.didCancel) {
console.log('User cancelled image picker');
}
else if (response.error) {
console.log('ImagePicker Error: ', response.error);
}
else if (response.customButton) {
console.log('User tapped custom button: ', response.customButton);
}
else {
const source = { uri: response.uri}
this.setState({
imageMessageSrc: source
});
this.uploadImage();
}
});
}
Then I try to uploadImage to firebase
uploadImage = () => {
console.log("Here");
const filename = this.randIDGenerator// Generate unique name
firebase
.storage()
.ref(`${firebase.auth().currentUser.uid}/sentPictures/${filename}`)
.putFile(this.state.imageMessageSrc)
.then(() => {
console.log("Here1");
})
.catch((error) => {
console.log(error);
})
When I delete putFile, error is gone, but obviously nothing happens to database.
Problem is related to the difference between filePath and fileUri. So, the solution is as below:
openPicker = () => {
const options = {
title: 'Fotoğraf Seç',
storageOptions: {
skipBackup: true,
path: 'images',
allowsEditing: true,
},
};
ImagePicker.showImagePicker(options, (response) => {
console.log('Response = ', response);
if (response.didCancel) {
console.log('User cancelled image picker');
}
else if (response.error) {
console.log('ImagePicker Error: ', response.error);
}
else if (response.customButton) {
console.log('User tapped custom button: ',response.customButton);
}
else {
var path = '';
if (Platform.OS == 'ios')
path = response.uri.toString();
else {
path = response.path.toString();
}
const image= {
image: response.uri.toString(),
path: path
};
this.uploadImage(image);
}
});
}
uploadImage = (image) => {
firebase.storage().ref(uploadUrl).putFile(image.path);
}
I realized that Firebase Storage putFile function doesn't work with image uri, instead it should be supplied with filePath. I used uri of this image to directly show image on the screen even before upload.
I'm using grid-stream and girdFsStorage library for getting image from mongodb.
I uploaded image to db was okay, but when I tried to get image from db failed.
I expected db.collection at gfs.files.findOne({ filename: req.params.filename }, (err, file) => {...}
but, this.db.collection is returned.
any ideas?
TypeError: this.db.collection is not a function
Here is my db connect
let db = mongoose.connect(init.mongoUrl)
.then(() => console.log('Connected to MongoDB...'))
.catch(err => console.error(('Could not connect to MongoDB...\n'), err))
and this is my code for getting an image from db
// Init stream
const gfs = Grid(db, mongoose.mongo);
api.get('/image/:filename', (req, res) => {
gfs.files.findOne({ filename: req.params.filename }, (err, file) => {
// Check if file
if (!file || file.length === 0) {
return res.status(404).json({
err: 'No file exists'
});
}
// Check if image
if (file.contentType === 'image/jpeg' || file.contentType === 'image/png') {
// Read output to browser
const readstream = gfs.createReadStream(file.filename);
readstream.pipe(res);
} else {
res.status(404).json({
err: 'Not an image'
});
}
});
});
It was because I didn'use
gfs.collection('uploads');
on .once('open', () => {...})
// Init gfs
let gfs;
conn.once('open', () => {
// Init stream
gfs = Grid(conn.db, mongoose.mongo);
gfs.collection('uploads');
});
You can see my example here:
https://github.com/qkreltms/mongodb_simple_file_upload_to_db_example/blob/master/app.js
about .collection() :
https://github.com/aheckmann/gridfs-stream/blob/c394e050d066a5c81c6dcdddad186b08a93d5f1f/lib/index.js#L75
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);
}
});
};