mongoose writing data into array object - node.js

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

Related

NodeJs: how to assign additional objects to mongoose query response JSON

Using mongoose I am querying a list of posts and would like to determine whether or not the user has liked the image or not within the query function by adding a boolean to the response JSON. I am trying to do this in a for loop.
However, when I console.log(), the post with the field returns correctly but does not amend it to the JSON.
My function:
function(req, res) {
var isLiked, likeCount;
Post
.find(/* Params */)
.then(posts => {
for (var index in posts) {
posts[index].isLiked = posts[index].likes.includes(req.headers.userid)
console.log(posts[index]) // does not show 'isLiked' field in JSON
console.log(posts[index].isLiked) // response is correct
}
res.send(posts) // does not have 'isLiked field
})
},
Post schema:
var postSchema = new Schema({
userId: {
type: String,
required: true
},
caption: {
type: String,
required: false
},
likes: [{
type: String,
}]
});
To add properties to queries objects you should convert them to JS objects:
function getPosts(req, res) {
Post.find(/* Params */).then((posts) => {
const result = [];
for (const post of posts) {
const postObj = post.toObject();
postObj.isLiked = postObj.likes.includes(req.headers.userid);
result.push(postObj)
}
res.send(result);
});
}
Cuz
Post.find()
is not return an object, you can set prop isLiked to posts[index] but it's private.
Easy way to fix it is use lean() method to get return object
Post.find().lean()
.then(//do what you want)

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 saving array as empty when not

First, here is the code:
Mongoose Schema
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
// Registration Form schema
var RegistrationFormSchema = new Schema;
RegistrationFormSchema.add({
studentFirst: { type: String, required: true },
studentLast: { type: String, required: true },
studentGrade: { type: String, required: true },
guardianFirst: { type: String, required: true },
guardianLast: { type: String },
guardianEmail: { type: String },
courseString: { type: String },
courseArray: { type: Array }
});
module.exports = mongoose.model('RegistrationForm', RegistrationFormSchema);
Relevant API Route
apiRouter.route('/registerNow')
.post(function(req, res) {
var newForm = new RegistrationForm();
console.log(req.body);
newForm.studentFirst = req.body.studentFirst;
newForm.studentLast = req.body.studentLast;
newForm.studentGrade = req.body.studentGrade;
newForm.guardianFirst = req.body.guardianFirst;
newForm.guardianLast = req.body.guardianLast;
newForm.guardianEmail = req.body.guardianEmail;
newForm.courseString = req.body.courseString;
newForm.save();
}
And this is inside of my controller, where I am making the request. Also making a request in Postman with the same response, so not sure if it is anything to do with how I am requesting, but want to include this to have more info for an answer.
$http.post('/api/registerNow', {
'studentFirst': vm.courseInfo.studentFirst,
'studentLast': vm.courseInfo.studentLast,
'studentGrade': vm.courseInfo.studentGrade,
'guardianFirst': vm.courseInfo.guardianFirst,
'guardianLast': vm.courseInfo.guardianLast,
'guardianEmail': vm.courseInfo.guardianEmail,
'courseString': vm.courseInfo.courseString,
'courseArray': ['asdasd', 'fasfasf', 'gasgasga']
});
Now that we have the relevant code, the question!
When I make my HTTP Post request to save to my database, it all saves, but it saves courseArray as an empty array '[]' no matter what, if it is empty or full.
I assume it's a Mongoose Schema issue.
In your route you're not setting the newForm.courseArray property with the data from the request. Mongoose is probably setting the default value as an empty array.
Try using the following code
apiRouter.route('/registerNow')
.post(function(req, res) {
var newForm = new RegistrationForm();
console.log(req.body);
newForm.studentFirst = req.body.studentFirst;
newForm.studentLast = req.body.studentLast;
newForm.studentGrade = req.body.studentGrade;
newForm.guardianFirst = req.body.guardianFirst;
newForm.guardianLast = req.body.guardianLast;
newForm.guardianEmail = req.body.guardianEmail;
newForm.courseString = req.body.courseString;
newForm.courseArray = req.body.courseArray; //This line is missing
newForm.save();
});

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 null checking before saving on nested schema array

I have an Schema model like this:
var propertySchema = new Schema({
name: {type: String, required: true},
surname: String
});
var objSchema = new Schema({
properties: [prepertySchema]
});
var accountSchema = new Schema({
objects: [objSchema]
});
mongoose.model('account', accountSchema);
Then i have the operations:
account.objects.push(null);
account.save(function(error, account) {
//Error checking and response
})
In that case, i'm getting a ValidationError because of the null value. This is expected. But, in the next operations:
var obj = {properties: null}
account.objects.push(obj);
account.save(function(error, account) {
//Error checking and response
})
Here the value is stored on database, and then i have an unexpected null value where it had been an array. Doing that with objects like this,
var obj = {
properties: [{name:'randname'}, null]
}
Also saves null values in the database that are prohibited to the data model.
I've read about validators, and middleware for checking things. Is there anyway to do this directly on the schema, or i have to parse the received object before i save it in the database? What is the best approach for this?
Well you could just use the model definitions for this. Even though you are embedding you can still do this but of course you do not want to actually save the objects to their own collection. Just feed them into the item as embedded:
var async = require("async"),
mongoose = require("mongoose"),
Schema = mongoose.Schema;
mongoose.connect('mongodb://localhost/prop');
var propertySchema = new Schema({
name: { type: String, required: true },
surname: String
});
var objSchema = new Schema({
properties: [propertySchema],
});
var accountSchema = new Schema({
objects: [objSchema]
});
var Account = mongoose.model( 'account', accountSchema );
var ObjMod = mongoose.model( 'ObjMod', objSchema, null, false );
var PropMod = mongoose.model( 'PropMod', propertySchema, null, false );
var account = new Account();
var prop = new PropMod({ "name": null });
var obj = new ObjMod({ properties: prop });
account.objects.push( obj );
account.save(function(err,account) {
if (err) throw err;
console.log( JSON.stringify( account, undefined, 4 ) );
});
So what happens there is the validation will work for each stage, in this case it will fail on the name of the property schema item not being a string or even if not included.

Resources