How to upload file using nodejs and express - node.js

I am lost on how to upload a file using nodejs. First time doing it. I have followed many 'guides' and none have worked. I try to format the code to fit with what I am doing and it fails. I am hoping someone can guide me in the right direction or help.
My code I have now is below.
startup.js model file
var mongoose = require("mongoose");
var startupSchema = new mongoose.Schema({
about_startup: {
startup_name: String,
startup_url: String,
short_description: String,
long_description: String,
tech_stack: String,
date_founded: Date,
image: //what do I put here?
},
social_media: {
blog: String,
twitter: String,
facebook: String,
linkedin: String,
email: String,
},
about_founder: {
founder_name: String,
social_media_founder: String
}
});
module.exports = mongoose.model("Startup", startupSchema);
Then my route is:
app.js
// CREATE add new startup to database
router.post("/new", function(req, res) {
// Get data from form
var about_startup = {
startup_name: req.body.startupname,
startup_url: req.body.url,
short_description: req.body.shortdescription,
long_description: req.body.longdescription,
tech_stack: req.body.techstack,
date_founded: req.body.foundeddate,
};
var social_media = {
blog: req.body.blog,
twitter: req.body.twitter,
facebook: req.body.facebook,
linkedin: req.body.linkedin,
email: req.body.email
};
var about_founder = {
founder_name: req.body.foundername,
social_media_founder: req.body.foundersocialmedia
};
//Pass data through | Write better explaination later
var newStartup = {about_startup: about_startup, social_media: social_media, about_founder: about_founder};
Startup.create(newStartup, function(err, newlyCreatedStartup){
if(err){
console.log(err);
} else {
// Redirect back to show all page
res.redirect("/startups");
}
});
});
This code works for what I want other than to upload the file. The html input for the image/file upload is:
<input class="form-control" type="file" name="image" accept=".jpg">

image: //what do I put here?
You can use String
Why String?
You can convert an image to a base64 string with ease
The string can be used to render the image in html
The string can be re-converted to a file
JSFiddle : Convert an image to a base64 string

Related

Load an image from Public Folder using string from MongoDB

I am trying to load images that are uploaded from a form to an index page. I have my public folder in app.js file mapped correctly and it is structured so that any image would be located at "/public/assets/img/filename.ext"
The schema I have for blog posts that are throwing errors is:
// schema setup
var mongoose = require("mongoose");
var postSchema = new mongoose.Schema({
title: String,
image: String,
uploadedImage: {
data: Buffer,
contentType: String,
},
dest: String,
postdata: String,
excerpt: String,
tag: String,
icon: String,
color: String,
featured: String,
keywords: String,
description: String,
slug: String,
create: {type: Date, default: Date.now},
author: {
id: {
type: mongoose.Schema.Types.ObjectId,
ref: "User"
},
username: String
},
});
module.exports = mongoose.model("Posts", postSchema);
This schema is filled by a form that I created that has the following route structure:
require("dotenv").config();
const express = require("express"),
router = express.Router(),
Posts = require("../models/blog"),
upload = require("../middleware/upload"),
path = require('path'),
fs = require('fs'),
middleware = require("../middleware"),
slugify = require('slugify');
// CREATE
router.post("/", middleware.isLoggedIn, middleware.isAdmin, upload.single('uploadedImage'), function(req,res){
var title = req.body.title;
var image = req.body.image;
var postdata = req.body.postdata;
var exceprt = req.body.excerpt;
var tag = req.body.tag;
var icon = req.body.icon;
var color = req.body.color;
var featured = req.body.featured;
var keywords = req.body.keywords;
var description = req.body.description;
var dest = req.file.filename;
var slug = slugify(title);
var uploadedImage = {
data: fs.readFileSync(path.join('./public/assets/img/' + req.file.filename)),
contentType: 'image/png'
};
var author = {
id: req.user._id,
username: req.user.username
};
// link dB to post values
var newPost= {title:title, slug:slug, image:image, postdata:postdata, excerpt:exceprt, tag:tag, icon:icon, color:color, featured:featured, author:author, keywords:keywords, description:description, dest:dest, uploadedImage:uploadedImage};
Posts.create(newPost, function(err, newlyCreated) {
if (err){
console.log(err);
}else{
console.log("slug:" + slug);
console.log(req.file.path);
res.redirect("/blog");
}
});
});
And to serve it in my EJS I am calling it like so inside of my loop:
<% Posts.forEach(function(post){ %>
<img src="/assets/img/<%= post.dest %>" class="img-fluid" />
<% }); %>
The result is the right path to my public folder, but I get a 404 error every time that says the file does not exist. I have checked and the files do exist so I am a little lost as to why I am getting that error. I have tested at local level and AWS C9 console, but when I push to a staging site on Heroku I get the error.
Any suggestions or code corrections would be helpful.
Anyone who uses Heroku will have this problem until you upgrade to a paid dyno. See this Heroku Doc that shows that the free tier goes to sleep. Since their system is transient and when a dyno sleeps it clears all uploaded files, that was the cause of my images not showing up in the templates. I tested this, and confirmed with a sales rep that because they are trying to remove their free tier this setting is fixed and will result in loss of data. Hope this helps someone, cheers!

How to use MongoDB Subdocument _id with EJS

I'm trying to get a subdocument from MongoDB using Mongoose, then pass the data to an EJS doc but I'm getting an Uncaught SyntaxError: Invalid or unexpected token because of the _id object. Ideally I would like the _id to be a string, but using toString() or toHexString() doesn't work.
Here are my basic Schemas:
var hikeSessionSchema = new mongoose.Schema({
hike_name: {type: String, required: true},
hike_date: {type: String, required: true},
mileage: {type: Number, required: true}
})
var hikerSchema = new mongoose.Schema({
username: {type: String, required: true},
log: [hikeSessionSchema]
})
var HikeSession = mongoose.model('HikeSession', hikeSessionSchema)
var Hiker = mongoose.model('Hiker', hikerSchema)
And here's my GET request:
app.set('view engine', 'ejs');
...
app.get('/users/:id/:hike', (req, res) => {
var id = req.params.id;
var hikeId = req.params.hike;
Hiker.findById(id, (err, hiker) => {
const hike = hiker.log.id(hikeId)
console.log(hike)
res.render('editHike', { data: hike })
})
When I console.log(hike) I get:
{
_id: 6125629447cec024c067c1da,
hike_name: 'Hike Name',
hike_date: '2021-08-04',
mileage: 10
}
I've tried saving the _id to a variable as a string, then replacing the _id with the variable, but it goes back to an object. I've also tried delete hike._id but that doesn't work either.
I need to be able to be able to reference the _id in the EJS doc for later use. Maybe there's a way to get the HikeSession object without the _id and then save the _id separately? How can I make this work? Thanks
I came up with a workaround by duplicating the object without the _id field, making a variable for turning _id into a string, then adding that variable to the new object.
app.get('/users/:id/:hike', (req, res) => {
var id = req.params.id;
var hikeId = req.params.hike;
Hiker.findById(id, (err, hiker) => {
var hikeData = hiker.log.id(hikeId)
var hike = (({ hike_name, hike_date, mileage }) => ({ hike_name, hike_date, mileage }))(hikeData);
var idStr = hikeData._id.toString()
hike.id = idStr;
res.render('editHike', { data: hike })
})
Then importing in the EJS file like this:
var data = <%- JSON.stringify(data) %>;
There's probably a better way to do it, but this worked.

Form not saving to MongoDB

I have been trying to get a form to submit to the database but every time I submit it only saves an id.
Below is my code in my app.js file for the post route the form submits to.
// CREATE add new startup to database
app.post("/startup-submit", function(req, res) {
// Get data from form
var startupname = req.body.startupname;
var url = req.body.url;
var shortdescription = req.body.shortdescription;
var longdescription = req.body.longdescription;
var techstack = req.body.techstack;
var foundeddate = req.body.foundeddate;
var blog = req.body.blog;
var twitter = req.body.twitter;
var facebook = req.body.facebook;
var linkedin = req.body.linkedin;
var email = req.body.email;
var foundername = req.body.foundername;
var foundersocialmedia = req.body.foundersocialmedia;
//Pass data through to page
var newStartup = {
startupname:startupname,
url: url,
shortdescription: shortdescription,
longdescription: longdescription,
techstack: techstack,
foundeddate: foundeddate,
blog: blog,
twitter: twitter,
facebook: facebook,
linkedin: linkedin,
email: email,
foundername: foundername,
foundersocialmedia: foundersocialmedia
};
Startup.create(newStartup, function(err, newlyCreatedStartup){
if(err){
console.log(err);
} else {
// Redirect back to show all page
res.redirect("/startups");
}
console.log(newlyCreatedStartup);
});
});
My model I am using is:
var mongoose = require("mongoose");
var startupSchema = new mongoose.Schema({
about_startup: {
startup_name: String,
url: String,
short_description: String,
long_description: String,
tech_stack: String,
date_founded: Date
},
social_media: {
blog: String,
twitter: String,
facebook: String,
linkedin: String,
email: String,
},
about_founder: {
name: String,
social_media_founder: String
}
});
module.exports = mongoose.model("Startup", startupSchema);
These should line up correctly, or am I off base on this? I am new to node and express so learning has been interesting. As for how I decided on the model and layout of the code, it is mostly from a previous project I did as part of a course. I wrote the above code out but referenced I guess is the best way of saying it to the old code.
I know the variables are all pulling the data because I console.log(variableName) each one to test it out. The model looks right to me but maybe I am missing something.
You should use the same variable name which you used in model. Your code should be like this. This code will perfectly suits you.
var newStartup = { about_startup: {}, social_media: {}, about_founder: {}};
newStartup.about_startup.startup_name = req.body.startupname;
newStartup.about_startup.url = req.body.url;
newStartup.about_startup.short_description = req.body.shortdescription;
newStartup.about_startup.long_description = req.body.longdescription;
newStartup.about_startup.tech_stack = req.body.techstack;
newStartup.about_startup.date_founded = req.body.foundeddate;
newStartup.social_media.blog = req.body.blog;
newStartup.social_media.twitter = req.body.twitter;
newStartup.social_media.facebook = req.body.facebook;
newStartup.social_media.linkedin = req.body.linkedin;
newStartup.social_media.email = req.body.email;
newStartup.about_founder.name = req.body.foundername;
newStartup.about_founder.social_media_founder = req.body.foundersocialmedia;
Startup.create(newStartup, function (err, newlyCreatedStartup) {
if (err) {
console.log(err);
} else {
// Redirect back to show all page
res.redirect("/startups");
}
console.log(newlyCreatedStartup);
});

mongoose writing data into array object

I have a schema that defines location as an array, into which I would like to write 2 strings (gmaps geocoding lat, long). So far I can't get it to work and can't figure out why. Any help is appreciated.
My schema:
var mongoose = require('mongoose');
var uniqueValidator = require('mongoose-unique-validator');
var Schema = mongoose.Schema;
//shop schema
var ShopSchema = new Schema({
name: { type: String, required: true, unique: true },
address: { type: String, required: true },
location: [{
latitude: String,
longitude: String
}]
});
ShopSchema.plugin(uniqueValidator);
module.exports = mongoose.model('Shop', ShopSchema);
post request:
.post(function(req, res) {
//create a shop
var shop = new Shop();
//set the shop information
shop.name = req.body.name;
shop.address = req.body.address;
//get lat and long before saving from gmaps API
//build gmaps API URL
var urlAddress = req.body.address.replace(/ /gi, '+');
var urlAPIKey = '&key=AIzaSyChkPdCaAaVZwYof8ZbKspokuYt41NlJ_0';
var url = 'https://maps.googleapis.com/maps/api/geocode/json?address=';
url = url.concat(urlAddress).concat(urlAPIKey);
//make a request
request({
uri: url,
method:"GET",
timeout: 1000
}, function(error, response, body) {
var gmaps = JSON.parse(body);
//display the geometry array
shop.location.latitude = gmaps.results[0].geometry.location.lat;
shop.location.longitude = gmaps.results[0].geometry.location.lng;
//save shop and check for errors
shop.save(function(err) {
if(err) {
return res.send(err);
}
else {
res.json({ message:'Shop created! '});
}
});
});
}) //closes .post on /shops
Basically I build an URL, make a request that returns JSON data, parse it, find it, and then try writing it. When I tried writing it without using an object (as properties on shop) it worked.
Thanks for the help
In your Shop schema, the location field is of type Array. You have to push the location object into the array after getting the response but you are trying to create an object instead of push object into array.
Change these two lines of your code from
shop.location.latitude = gmaps.results[0].geometry.location.lat;
shop.location.longitude = gmaps.results[0].geometry.location.lng;
to
shop.location.push({ latitude: gmaps.results[0].geometry.location.lat.toString(), longitude: gmaps.results[0].geometry.location.lng.toString() });

Empty objects using app.post and AngularJS + mongoose on node.js

My REST API is posting empty objects.
I am getting the value from req.body.name
If I log it console.log(req.body.name); I get the value on my console.
POST:
{ name: 'typing any name', status: null }
typing any name
So the workflow between my frontend (angular.js), the form and the backend (node.js, express, mongoose) seems to work. Now I POST the value, but I get an empty object in my mongoDB.
{"_id":"543a50a974de6e2606bd8478","__v":0}
app.post('/api/offers', function (req, res){
var offer;
console.log("POST: ");
console.log(req.body);
console.log(req.body.name);
offer = new OfferModel({
name: req.body.name,
value: req.body.value,
title: req.body.title,
content: req.body.content,
});
offer.save(function (err) {
if (!err) {
return console.log("created offer" + req.body.name);
} else {
return console.log(err);
}
});
return res.send(offer);
});
And here is the model:
var offerSchema = mongoose.Schema({
offer : {
name : String,
value : String,
title : String,
content : String,
image : String,
start : String,
end : String,
targets : String,
beacons : String,
published : String
}
});
var OfferModel = mongoose.model('Offer', offerSchema);
Schema is incorrect, must be like this:
var offerSchema = mongoose.Schema({
name : String,
value : String,
title : String,
content : String,
image : String,
start : String,
end : String,
targets : String,
beacons : String,
published : String
});

Resources