Load an image from Public Folder using string from MongoDB - node.js

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!

Related

Mongoose validation and GridsFS

I would like add a mongoose validation in my code but I don't have a ".save method" in my code. It's because I use GridFS who to manage the save in the Database.
My question is simple. How get I a mongoose error with a other method.
This is a example of code.
First part, the schema
var mySchema = new Schema({
name: {
type: String,
required: true
},
color: {
type: String,
required: true
}
});
mongoose.model('mySchema', mySchema);
Second Part, the JS Code
Normally, you have this code.
var mySchema = mongoose.model('mySchema');
function upload(req, res){
var name = req.body.name;
var color = req.body.color;
var myUpload = new MySchema({
name: name,
color: color
})
myUpload.save(function(err){
if(err){
console.log(err)
}
})
}
But me, I don't have this code because GridFS manage all. So, how catch a error while schema execution if i don't have this code, but gridFS ?

How to upload file using nodejs and express

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

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);
});

MongoError: E11000 duplicate key error

i'm making a simple blog app using nodejs + express, i can add first post without a problem but when i try to add second post i got his error { MongoError: E11000 duplicate key error collection: restful_blog_app_v2.blogs index: username_1 dup key: { : null }
this is my schema
var mongoose = require("mongoose");
var passportLocalMongoose = require("passport-local-mongoose");
var BlogSchema = new mongoose.Schema({
title: String,
image: String,
body: String,
created: {
type: Date,
default: Date.now
},
author: {
id: {
type: mongoose.Schema.Types.ObjectId,
ref: "User"
},
username: String
}
});
BlogSchema.plugin(passportLocalMongoose);
module.exports = mongoose.model("Blog", BlogSchema);
this is the user schema
var mongoose = require("mongoose");
var passportLocalMongoose = require("passport-local-mongoose");
var UserSchema = new mongoose.Schema({
username: String,
password: String,
});
UserSchema.plugin(passportLocalMongoose);
module.exports = mongoose.model("User", UserSchema);
this is the create new post route
app.post("/blogs", isLoggedIn, function (req, res) {
req.body.blog.body = req.sanitize(req.body.blog.body);
var title = req.body.blog.title;
var image = req.body.blog.image
var body = req.body.blog.body;
var created = req.body.blog.created;
var author = {
id: req.user._id,
username: req.user.username
}
var newPost = {
title: title,
image: image,
body: body,
created: created,
author: author
}
Blog.create(newPost, function (err, newBlog) {
if (err) {
console.log(err);
res.render("new");
} else {
console.log(newBlog);
res.redirect("/blogs");
}
});
});
I've tried to dropped the entire database using db.dropDatabase() from the mongo console but the problem still persist, not sure what to do now
This is caused by passport-local-mongoose, which, according to its fine manual, makes username a unique field by default.
You have added this plugin to BlogSchema, which seems like you initially had the user data in that schema but moved it to a separate schema (UserSchema) and forgot to remove it from the former.
Start by not using it for BlogSchema, and you also need to drop the unique index on username on the blogs collection.
Can you try deleting your Schema and again send the value? I was getting the same issues. I solved with the above idea.

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() });

Resources