Form not saving to MongoDB - node.js

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

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!

Pass schema value in place of array for creating document using mongoose

I want to pass schema details in the the place of array in my code. How can I do this in my controller ?
module.exports.registerAdmin = (req, res, next) =>{
var admin = new Admin();
admin.email = req.body.email;
admin.password = req.body.password;
admin.firstName = req.body.firstName;
admin.lastName = req.body.lastName;
const reqq = crypto.createHash('md5').update(admin.companyName).digest('hex');
let valueNum = reqq.match(/\d/g).join("").toString().substring(0,6);
admin.companyID = valueNum;
console.log(valueNum);
const arrayObj = [{con:'IND'},{con:'USA'},{con:'JPN'}];
admin.save((err, doc) =>{
if(!err){
res.send(doc);
var thingSchema = new mongoose.Schema({}, { strict: false, collection: valueNum });
var Thing = mongoose.model(valueNum , thingSchema);
var thing = new Thing(arrayObj);
thing.save();
console.log(thing);
in the place of arrayObj, I need to pass my Schema model details so that I can use it to create document inside the collection which I am creating in the code.
EDIT:-
Schema module file.
var adminSchema = new mongoose.Schema({
firstName : {
type: String,
required: "First name can't be empty."
},
lastName : {
type: String,
required: "Last name can't be empty."
},
email : {
type: String,
required: "Email can't be empty.",
unique: true
},
password : {
type: String,
required: "Password can't be empty",
minlength: [6 ,"Password must be atleast 6 character long."]
}
saltSecret: String //this is user for encryption and decryption of password
});
mongoose.model('Admin', adminSchema);
MongoDB nested object:-
enter image description here
If you're trying to pass the admin document to new Thing(), you would first try to get its doc.schema.obj or doc.schema.paths (if you need the same _id), then you get all the propreties in an array, make an object with key value pairs and pass it to your new Thing(arrObj).
admin.save((err, doc) =>{
if(err) return err;
res.send(doc);
let arr = Object.keys(doc.schema.obj);
let arrObj = {};
arr.map(key => arrObj[key] = doc[key]);
var thingSchema = new mongoose.Schema({}, { strict: false, collection: valueNum });
var Thing = mongoose.model(valueNum , thingSchema);
var thing = new Thing(arrObj);
thing.save();
console.log(thing);
})
I noticed your sending the document (res.send(doc)) before instanciating your Thing model, sure, res.send() only ends the HTTP response, and does not stop you code from running, but that's the only response you'd be able to send. You can only send one response.

Mongoose saving for populate

I'm new to Mongoose and Nodejs developement in general and I've got a bit of confusion around how to properly set up saving my records. Here are my two schemas:
Download
var mongoose = require("mongoose");
var Schema = mongoose.Schema;
var downloadSchema = Schema({
title : String,
description : String,
_project : { type: Schema.Types.ObjectId, ref: 'Project' }
});
module.exports = mongoose.model('Download', downloadSchema);
Project
...
var projectSchema = Schema({
name : String,
url : String,
pwd : String,
_downloads : [{type: Schema.Types.ObjectId, ref: 'Download' }]
});
module.exports = mongoose.model('Project', projectSchema);
This appears to be working correctly. The documentation explains my use-case of saving a download and linking a project, but I'm not sure how to properly populate the Project._downloads. Here's what I've done:
Express route handler:
function createDownload(req, res) {
// the Project Id is passed in the req.body as ._project
var dldata = req.body;
Project.findOne({ _id : dldata._project }, function(err, project) {
var dload = new Download(dldata);
dload.save( function (err, download) {
project._downloads.push(download._id);
project.save( function(err){
var msg = {};
if(err) {
msg.status = 'error';
msg.text = err;
}else {
msg.status = 'success';
msg.text = 'Download created successfully!';
}
res.json(msg);
});
});
});
}
This seems overcomplicated to me. Am I supposed to be manually pushing to the ._downloads array, or is that something Mongoose is supposed to handle internally based on the schema? Is there a better way to achieve it so that I can do:
Download.find().populate('_project').exec( ...
as well as:
Project.findOne({_id : _projectId}).populate('_downloads').exec( ...
According to the mongoose docs there are 2 ways to add subdocs to the parent object:
1) by using the push() method
2) by using the create() method
So I think that your code can be a bit simplified by eliminating the operation of saving a new Download item:
function createDownload(req, res) {
var dldata = req.body;
Project.findOne({ _id : dldata._project }, function(err, project) {
// handle error
project._downloads.push(dldata);
project.save(function(err) {
// handle the result
});
});
}
or
function createDownload(req, res) {
var dldata = req.body;
Project.findOne({ _id : dldata._project }, function(err, project) {
// handle error
project._downloads.create(dldata);
project.save(function(err) {
// handle the result
});
});
}

mongo insert in nodejs for loop only inserting one from array

im building an application to collect votes for a live event.
the api doesnt give us option to select users from a time frame so im polling the endpoint every second.
i currently have 13 entries that return from the endpoint, i parse them into and array and for loop around them setting my mongoose schema with the attributes and trying to save them, but when i do
db.votes.count() my result is always 1
my node module looks like
var express = require('express');
var unirest = require('unirest');
var voteSchema = require(GLOBAL.rootdir + '/modules/voting/models/votes');
var seconds = 0;
var interval = 1000;
express({
votePoller : setInterval(function () {
seconds++;
if (typeof GLOBAL.accessToken != 'undefined') {
var Request = unirest.get('https://api.domain.io/api/v1/guests');
Request
.header('Accept', 'application/json')
.header('Content-Type', 'application/json; charset=utf-8')
.header('Authorization', 'Bearer ' + GLOBAL.accessToken)
.end(function (response) {
if(response.code === 200){
var votesModel = new voteSchema;
var payloadArray = JSON.parse(response.raw_body);
for(var i in payloadArray.guests){
console.log(i);
console.log(payloadArray.guests[i]);
votesModel.ctid = payloadArray.guests[i].id;
votesModel.email = payloadArray.guests[i].username;
votesModel.voteStatus = 0;
votesModel.createdAt = new Date(1000 * payloadArray.guests[i].created_at);
votesModel.save(function(err) {
if (err) {
console.log(err);
console.log({ message: err });
} else {
console.log({ message: 'vote saved' });
}
});
console.log('Done');
}
}
});
}
console.log(seconds);
}, interval)
});
var votePoller = express;
module.exports = votePoller;
my mongoose model is
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var votesSchema = new Schema({
ctid: { type: String, required: true, unique: true },
fullName: { type: String},
email: { type: String, required: true, unique: true },
mobileNumber: { type: String },
vote: { type: Number},
voteStatus: Boolean,
createdAt: Date
});
var Votes = mongoose.model('Votes', votesSchema);
module.exports = Votes;
the console log counts out each i in the array so why the save function isn't being fired is stumping me
Thanks in advance
You need to use an async function to do an async for loop, there are many answer on here for that code. I would suggest a control flow library like async or if using a new version of node, use native promises instead. Promises all method is the best way to achieve this.

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