hope someone can help me with this:
I am working on a Node/Express/Mongo CRUD app where every post/document has ONE image. I am using multer and cloudinary for uploading the images. However, I want users to be able to upload multiple images to each post. Ideally, the image urls/paths and IDs would be stored in arrays in my database.
I have been trying and researching for hours now but cannot seem to make it work, and there is no tutorial out there explaining how this (simple) task can be achieved using multer and cloudinary.
This is the code I am using to upload ONE image per post, which is working:
// CREATE Route - add new post to DB
router.post("/", middleware.isLoggedIn, upload.single('image'), function(req, res) {
cloudinary.v2.uploader.upload(req.file.path, function(err, result) {
if(err) {
req.flash('error', err.message);
return res.redirect('back');
};
// add cloudinary url for the image to the post object under image property
req.body.post.image = result.secure_url;
// add image's public_id to post object
req.body.post.imageId = result.public_id;
// add author to post
req.body.post.author = {
id: req.user._id,
username: req.user.username
}
Post.create(req.body.post, function(err, post) {
if (err) {
req.flash('error', err.message);
return res.redirect('back');
}
res.redirect('/posts/' + post.id);
});
});
});
How would I need to change this code in order to achieve this goal?
Thanks in advance for your help!
The upload API currently only supports a single file upload at a time, it does have a high concurrency rate (of about 40-50 concurrent calls) so you can use multi-threads to upload many files at once.
You can also use asynchronous calls, and tell Cloudinary to do the upload in the background by adding the async parameter and setting it to true.
Related
I have an API in one nodejs project as below which receive multiple attachment from UI:
const upload = multer()
router.post('/upload', upload.array("attachments"),controller.getSomething);
getSomething is supposed to call another POST API using Axios only, which is in another NodeJs project which accept these attachments and process it. It as well accept multiple files via multer.
I am unsure how could i send multiple files as a request from one Nodejs project to another at once. could you please favour.
I had to set formdata as below:
const formData=new FormData();
for(let file of req.files){
formData.append("attachments",file.buffer,file.originalname);
}
And passed the formdata to other api via axios.
You can do the following steps:
When you upload the temporary files (coming from UI), save them in the temporary folder.
Pass all the files names to the POST API using Axios.
In the post API, read all the files from the temporary folder and stream them to the destination.
controller.getSomething = (req, res, next) => {
// get the file names
const fileNames = req.files.map(filename => filename);
// now post this filenames to the
axios.post('/pathname', {fileNames})
// or, you can use get request
}
Reading files in the post Request:
var promises= ['file1.css', 'file2.css'].map(function(_path){
return new Promise(function(_path, resolve, reject){
fs.readFile(_path, 'utf8', function(err, data){
if(err){
console.log(err);
resolve(""); //following the same code flow
}else{
resolve(data);
}
});
}.bind(this, _path));
});
Promise.all(promises).then(function(results){
//Put your callback logic here
response.writeHead(200, {"Content-Type": "text/css"});
results.forEach(function(content){response.write(content)});
response.end();
});
#copied from this link. You should check the different answers that can help you.
I've created a SNS web application (using node.js) where people can upload pictures (using cloudinary) into collections.
The application works perfectly on a cloud-based IDE I use for writing code; however, after pushing it to heroku, the image upload no longer works. I don't get any error message in my console, even though I think it should be console.logging it, however the error flash happens and the image doesn't upload.
Here is my code:
router.post("/", middleware.isLoggedIn, upload.single('image'), function(req, res){
cloudinary.v2.uploader.upload(req.file.path, function(err, result) {
if (err) {
//if error
console.log(err.message);
req.flash("error", "Can't upload image, try again later.");
return res.redirect("back");
}
//else
// add cloudinary url for the image to the campground object under image property
req.body.image = result.secure_url;
req.body.imageId = result.public_id;
// add author to campground
req.body.author = {
id: req.user._id,
username: req.user.username
};
I've tried searching other posts for a possible reason; but I can't find anything that matches my situation. If anyone can help...please, your advice would be greatly appreciated!
Thank you.
Sorry! The problem was the CLOUD_NAME config variable had '' marks around it.
If anyone is having similar issues, try removing the quotes around the name variable.
I am implementing a web app using MEAN Stack and Angular 6. There I want to submit a form with file upload. '.png' files should be uploaded.
I want to save the file in a different file server and send the url to the image.Currently I upload files into a folder in my project and save the image in db (I used ng2fileupload and multer for that.). Then it saves like this.
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAV4AAAFUCAYAAABssFR8AAAK..."
But I want to save the image url and the image should be retrived by the url. Does anyone can explain a proper method for that?
I faced the same problem a month ago and find out a solution to this problem. Though I haven't used multer in the app.
From my frontend, I will be sending an object to Node API endpoint /event which will look like:-
let img = {
content: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUg...",
filename: 'yourfile.png'
}
At the backend, I'm using Cloudinary to store my images (Its free plan allows 10GB storage) and returns secure https URLs. So install it using npm i cloudinary and require in your api.js file.
And add the below configuration
cloudinary.config({
cloud_name: 'yourapp',
api_key: 'YOUR_KEY',
api_secret: 'YOUR_SECRET_KEY'
});
Last Step:- (Not so optimized code)
Let say I have an event Schema which has images array, where I'll be storing the URLs returned by cloudinary.
app.post('/event', (req, res) => {
try {
if (req.body.images.length > 0) {
// Creating new Event instance
const event = new Event({
images: [],
});
// Looping over every image coming in the request object from frontend
req.body.images.forEach((img) => {
const base64Data = img.content.split(',')[1];
// Writing the images in upload folder for time being
fs.writeFileSync(`./uploads/${img.filename}`, base64Data, 'base64', (err) => {
if (err) {
throw err;
}
});
/* Now that image is saved in upload folder, Cloudnary picks
the image from upload folder and store it at their cloud space.*/
cloudinary.uploader.upload(`./uploads/${img.filename}`, async (result) => {
// Cloudnary returns id & URL of the image which is pushed into the event.images array.
event.images.push({
id: result.public_id,
url: result.secure_url
});
// Once image is pushed into the array, I'm removing it from my server's upload folder using unlinkSync function
fs.unlinkSync(`./uploads/${img.filename}`);
// When all the images are uploaded then I'm sending back the response
if (req.body.images.length === event.images.length) {
await event.save();
res.send({
event,
msg: 'Event created successfully'
});
}
});
});
}
} catch (e) {
res.status(400).send(e);
}
});
P.S. Go ahead and suggest some optimization solution for this code here
How do I create a web gallery and uploading, storing and displaying images via nodejs and mongodb?
I have tried to write some code myself, but don't manage to solve the problem.
Do someone have a link or tutorial that helps me solve the problem?
It is not recommended to store whole images on databases. It can be done but based on similar questions on stack overflow it is better to store images on your file system. That can be done by using themulterand fs module to handle the upload and store it on the file system. You can even use an image proccessor to confirm that what was uploaded was really an image and not something else. I recommend using the sharp module found on npm to do that. This way you are sure that nothing can go wrong and you can even resize images before storing. Here is some code for this using express.js:
var multer = require('multer');
var uploadPicture = multer({
dest: 'temp/'
});
var sharp = require('sharp');
app.post('/upload', uploadPicture.single('profileIcon'), function (req,res) {
fs.readFile(req.file.path, function (err, data) {
if (err) res.end('UNRESOLVABLE ERROR');
sharp(data).resize(200, 200).toFile('./photos/pic.jpg', function (err, info) {
//DELETE THE TEMPORAL FILE
fs.unlink(req.file.path, function (error) {
if (error) res.end('UNRESOLVABLE ERROR'); //CODE 3 ALARM
res.end('success');
});
}
I am learning node.js at the moment and I am creating a little application where I can upload images and display them in a gallery.
Currently I have a form which uploads the image to the server via POST
extends ../layout
block content
.col-sm-6.col-sm-offset-3
h1 control panel
form(action="/upload", method="POST",
enctype="multipart/form- data")
input(type="file", name='image')
input(type="submit", value="Upload Image")
The file is then inserted to a mongodb using mongoose
exports.upload = function (req, res) {
fs.readFile(req.files.image.path, function (err, data) {
var imageName = req.files.image.name;
if(!imageName){
console.log("seems to be an
error this file has not got a name");
res.redirect("/");
res.end();
}else{
var newimage = new Image();
newimage.img.data = fs.readFileSync(req.files.image.path);
newimage.img.name = imageName;
newimage.save(function (err, a) {
if (err){
console.log("There was an error saving the image")
res.redirect("/");
res.end();
}
res.redirect("/gallery");
});
}
});
}
In my gallery controller I query the database for all the images and pass them to front-end.
exports.gallery = function (req, res) {
Image.find({}, function(err, image){
if (err)
res.send(err);
else
res.render("site/gallery", {images: image });
});
}
And then in my gallery I try create a new image tag for each of the images
extends ../layout
block content
h1 Gallery
each image in images
img(src='#{image.img.data}')
My problem is that I keep getting a 404 error because the browser cannot find the image.
But I have a feeling that I might be going about this the wrong way. I have seen GridFS but I feel that it is not suitable for this app as the amount of images in the gallery will be less than 20 max. Am I going about the right way to do this or should I be storing the images on the server and retrieving them that way?
You would typically upload the images to your server's machine filesystem or to a static assets cloud hosting service like AWS S3, and store only the URLs of the images in your database.
You could also use a solution like Cloudinary.