Array not passing in express to mongo - node.js

I'm trying to pass an array to MongoDB using express post request.
app.post('/createGroup', (req, res) => {
const { title, description, tenants } = req.body;
const group = {
title: title,
description: description,
tenants: tenants,
};
console.log(tenants);
const newGroup = new Group(group);
newGroup.save();
res.redirect('/'); });
Everything works just fine till here. if I log console.log(tenants) returns and array of ids
[ 'd8ef412c-7947-4500-8e7f-73157e30961e', 'a515dfa8-a272-4d95-87d2-a1a4f22175b5' ]
But the tenants are not passed to MongoDB.
Instead, I get
_id: 623639bde8f1bdfc6eab462e
title: "Nitro"
description: "Its a Group"
tenants: Array
created_at: 2022-03-19T20:14:53.268+00:00
__v: 0
Here is my Schema,
const GroupSchema = new mongoose.Schema({
title: String,
description: String,
tenants: [{type: String}],
created_at: {
type: Date,
default: Date.now
}
});
The HTML form is here.
<form class="create-group" action="/createGroup" method="POST">
<div class="form-group">
<label for="title">Group Title</label>
<input type="text" class="form-control" id="title" name="title" placeholder="Group Title / Name">
</div>
<div class="form-group">
<label for="description">Group Description</label>
<textarea class="form-control" id="description" name="description" rows="3"
placeholder="Group Description"></textarea>
</div>
<div>
<fieldset>
<legend>
Tenants
</legend>
<% tenants.forEach(function(tenant) { %>
<div class="form-check">
<input class="form-check-input" type="checkbox" value="<%= tenant.tenantId %>" name="tenants[]">
<label class="form-check-label" for="<%= tenant.tenantId %>">
<%= tenant.tenantName %>
</label>
</div>
<% }) %>
</fieldset>
</div>
<div class="form-group">
<button type="submit" class="btn btn-primary">Create Group</button>
</div>
</form>

I believe the issue is in your schema, you should be defining tenants array property like this
tenants: [String]
or you can do
tenants: { type: [String] }

Related

Update data in mongodb with input valors

I have three input to obtain three different values. Im using express.js , node.js, mongodb and ejs templates.
<form action="/save-profile/<%= user.id %>/<%= user.name %>/<%= user.lastname %>/<%= user.description %>" method="POST">
<div class="input-group mb-3">
<span class="input-group-text" id="basic-addon1">Name</span><%= user.username %>
<input type="text" class="form-control" placeholder="'John'" aria-label="Username" name="username">
<span class="input-group-text">lastName</span><%= user.lastname %>
<input type="text" class="form-control" placeholder="" aria-label="Server" name="lastname">
</div>
<div class="input-group">
<span class="input-group-text">Description:</span>
<textarea class="form-control" aria-label="With textarea" placeholder="" name="description"><%= user.description %></textarea>
</div>
</p><br>
<button class="btn btn-primary mb-10 btn-lg">Save</button>
</div>
</div>
In js file:
router.post('/save-profile', async (req, res) => {
const profile_id = await User.findById({ _id: req.body.id })
const updatedName = await User.findOneAndUpdate({ username: req.body.username})
const updatedlastname = await User.findOneAndUpdate({ apellido: req.body.lastname })
const updatedDescription = await User.findOneAndUpdate({ description: req.body.description })
console.log(profile_id,updatedName,updatedApellido,updatedDescription)
res.redirect('/profile')})
I tried to do it with a get but it didn't work
Firstly, action attribute in the form tag accepts the path where you are handling the form data. You only need to pass the user.id, there's no need to pass the other fields for this use-case.
<form action="/save-profile/<%= user.id %>" method="POST">
...
</form>
Secondly, in your route handler, the database record can be updated using only a single findOneAndUpdate call. You don't need to call it multiple times for every field if you're only going to update a single record.
The path written in action attribute will appear as /save-profile/1, for instance, in your route handler. Value preceding /save-profile/ i.e. 1 can be accessed by modifying the path in route handler as /save-profile/:id and in the callback you can get it by req.params.id
Finally you have this.
router.post('/save-profile/:id', async (req, res) => {
const response = await User.findOneAndUpdate(
{ _id: req.params.id },
{
username: req.body.username,
apellido: req.body.lastname,
description: req.body.description
},
{ new: true }
)
// Do something with response
res.redirect('/profile')
})

Mongoose use user input to find results in DB with express.js?

I'm new to mongoose/mongo and express so I'm not quiet sure how to go about this. So basically I'm trying to use checkboxes to sort of "filter" results in my database.
Here's an example of something in my db:
{ "location" : "PHARMACY",
"region" : "SOCAL",
"system" : "WITS",
"contact" : "SMITH",
"membership" : "TIER1" }
So far I've only figured out how to hard code it like this, where I do Environment.find({region: "SOCAL"}) and it spits out all the db entries that contain SOCAL as a region:
var express = require("express"),
app = express(),
mongoose = require("mongoose"),
bodyParser = require("body-parser");
mongoose.connect("mongodb://localhost/epims", {
useNewUrlParser: true,
useUnifiedTopology: true
});
app.use(bodyParser.urlencoded({ extended: true }));
app.set("view engine", "ejs");
//schema setup
var environmentSchema = new mongoose.Schema({
name: String,
region: String,
system: String,
contact: String,
membership: String,
});
var Environment = mongoose.model("Environment", environmentSchema);
app.get("/environments/show", function(req, res) {
//find environment with selected parameters
Environment.find({region: "SOCAL"}, function(err, foundEnvironment) {
if (err) {
console.log(err);
} else {
//render show template with that env
res.render("show", { environment: foundEnvironment });
}
});
});
How do I make it so this search through the database changes based on what selections are made?
Here is my select form if anybody needs to see that as well
<form action="/environments" method="GET">
<legend>Locations</legend>
<input type="checkbox" name="location" value="PHARMACY">
<label for="PHARMACY">PHARMACY</label>
<input type="checkbox" name="location" value="OFFICE">
<label for="OFFICE">OFFICE</label>
<input type="checkbox" name="location" value="STORE">
<label for="STORE">STORE</label>
<legend>Regions</legend>
<input type="checkbox" name="region" value="SOCAL">
<label for="SOCAL">SOCAL</label>
<input type="checkbox" name="region" value="NORCAL">
<label for="NORCAL">NORCAL</label>
<input type="checkbox" name="region" value="WA">
<label for="WA">WA</label>
...
Submit
</form>
You can pass the search parameters via the search query:
/environments/show?location=OFFICE&location=STORE&region=SOCAL&region=NORCAL
The GET request produce this database query:
{
region: { '$in': [ 'SOCAL', 'NORCAL' ] },
location: { '$in': [ 'OFFICE', 'STORE' ] }
}
app.get("/environments/show", function (req, res) {
let region = [req.query.region || []].flat();
let location = [req.query.location || []].flat();
let query = {
region: {
"$in": region
},
location: {
"$in": location
}
};
Environment.find(query, function (err, foundEnvironment) {
if (err) {
console.log(err);
} else {
//render show template with that env
res.render("show", { environment: foundEnvironment });
}
});
});
<form action="/environments/show" method="GET">
<legend>Locations</legend>
<input type="checkbox" name="location" value="PHARMACY">
<label for="PHARMACY">PHARMACY</label>
<input type="checkbox" name="location" value="OFFICE">
<label for="OFFICE">OFFICE</label>
<input type="checkbox" name="location" value="STORE">
<label for="STORE">STORE</label>
<legend>Regions</legend>
<input type="checkbox" name="region" value="SOCAL">
<label for="SOCAL">SOCAL</label>
<input type="checkbox" name="region" value="NORCAL">
<label for="NORCAL">NORCAL</label>
<input type="checkbox" name="region" value="WA">
<label for="WA">WA</label>
...
<button type="submit">Submit</button>
</form>

Firebase auth.$createUserWithEmailAndPassword complaining about email format

On firebase, using vue.js, when registering and trying to add more info about the user to the database I am running into a really frustrating error when the app tries to write the newUser email to Firebase. The app simply breaks when I the email is part of an object.
I am using the createUserWithEmailAndPassword(this.email, this.password) method to authorise and register a user (on the user list) and then calling a function to register the same user on the database.
this is the error i am getting:
As you can see the console is outputting a string joaoalvesmarrucho#gmail.com while complaining it's not a string. :/
I have converted the email to a string with no success.
HTML TEMPLATE:
<form v-on:submit.prevent>
<div class="control">
<input class="input" v-model="newUser.name" type="text" placeholder="Your Display Name">
</div>
<div class="control">
<input class="input" v-model="newUser.email" id="email" type="email" placeholder="joew#bloggs.com" >
</div>
<div class="control">
<input id="password" v-model="newUser.password" class="input" type="password" placeholder="Password">
</div>
<div class="control">
<input id="confirm_password" class="input" type="password" placeholder="Retype your password" v-on:keyup="checkRetypePassword">
</div><span id='message'></span>
<button type="submit" class="button is-primary" v-on:click="signUp">Register</button><span> or </span><button type="submit" class="button is-primary" v-on:click="googleSignUp">Register with Google</button>
</form>
SCRIPT:
export default {
data: function() {
return {
users: usersRef,
// username: this.$store.getters.getUser.displayName,
newUser: {
name: '',
email: '' ,
password: '',
uid: '',
}
};
},
methods: {
signUp: function() {
var jsonEmail = JSON.stringify(this.newUser.email);
var email = jsonEmail.replace(/\"/g, "");
console.log(email);
firebaseApp.auth().createUserWithEmailAndPassword(this.email, this.password).then(function(user) {
logUser(user); // callback push user to database
console.log(email);
}, function(error) {
alert(error.message + error.code);
});
function logUser(user) {
usersRef.push(this.newUser);
this.name = '';
this.email = ''; // ERROR: "email" must be a valid string
this.uid = firebaseApp.auth().currentUser.uid;
}
Could you please give me a hint?
Got it working simply by getting the value from the email field. Hope this is useful to somebody in the future:
HTML
<form v-on:submit.prevent>
<div class="control">
<input class="input" v-model="user.name" type="text" placeholder="Your Display Name">
</div>
<div class="control">
<input class="input" v-model="user.email" id="email" type="email" placeholder="joew#bloggs.com" >
</div>
<div class="control">
<input id="password" v-model="user.password" class="input" type="password" placeholder="Password">
</div>
<div class="control">
<input id="confirm_password" class="input" type="password" placeholder="Retype your password" v-on:keyup="checkRetypePassword">
</div><span id='message'></span>
<button type="submit" class="button is-primary" v-on:click="signUp">Register</button><span> or </span><button type="submit" class="button is-primary" v-on:click="googleSignUp">Register with Google</button>
</form>
SCRIPT:
export default {
data: function() {
return {
users: usersRef,
user: {
name: '',
email: '',
},
users: [{
name: 'John Doe',
email: 'john.doe#gmail.com',
uid: "should be actual User UID",
}],
};
},
methods: {
signUp: function() {
firebaseApp.auth().createUserWithEmailAndPassword(email.value, password.value).then(function(user) {
}, function(error) {
alert(error.message + error.code);
});

Editing text on a page in node js

I am trying to implement a simple edit feature in my app. In my profile.handlebars file, I have an edit button. When clicked, I'd like the user's information to appear in the text input fields on the form in order to allow the user to edit their existing information.
Right now, they would have to input all of their information over again (and every field in the form would need to be filled out due to validation that I have implemented), click Submit, and their profile can be updated. Is this possible without using a framework (like Angular)? For example, in LinkedIn, a user can hover over a section of their profile causing the edit buttons to highlight, then click a single edit button, and they're instantly in editing mode. That might be too advanced for my purposes right now, but eventually, I'd love to have functionality like that.
I have a post request in my routes file to handle a user posting information to their profile:
router.post('/add', function(req, res) {
req.checkBody({
'city': {
errorMessage: 'Please enter your city'
},
'state': {
errorMessage: 'Please enter your state',
notEmpty: true
},
'zip': {
errorMessage: 'Please enter your zip code',
notEmpty: true
},
'about': {
errorMessage: 'Please briefly describe yourself',
notEmpty: true
}
});
console.log("req.user " + req.user);
var errors = req.validationErrors();
if (errors) {
res.render('profile', {
errors: errors
});
} else {
var user_info = new User_Info({
city: req.body.city,
state: req.body.state,
zip: req.body.zip,
about: req.body.about,
user_name: req.user.username
});
user_info.save(function(err, user_info) {
if (err) throw err;
});
res.redirect('profile/' + req.user.username)
}
})
Then, I have my profile.handlebars file:
{{#if errors}}
Uh oh! Something went wrong. Please review the below errors, and try again.<br><br>
<ul>
{{# each errors }}
<li style="color: red">{{this.msg}}</li>
{{/each}}
</ul>
{{else}}
<h3 align="center">Profile ({{user_name.name}})</h3>
<div class="row">
<div class="col-md-4 col-md-offset-4">
<div class="thumbnail" style="border-radius: 12px">
<div class="caption">
<p>City: {{# each information }} {{this.city}} {{/each}}</p>
<p>State: {{# each information }} {{this.state}} {{/each}}</p>
<p>Zip: {{# each information }} {{this.zip}} {{/each}}</p>
<p>About: {{# each information }} {{this.about}} {{/each}}</p>
<div class="btn-group">
<button type="Edit" class="btn btn-danger dropdown-toggle deleteLocation" data-id="{{this.id}}">Edit</button>
</div>
</div>
</div>
</div>
</div>
<br>
<center>
<form method="POST" action="/users/add">
<input type="text" name="city" placeholder="City" style="text-align: left">
<br><br>
<input type="text" name="state" placeholder="State" style="text-align: left">
<br><br>
<input type="text" name="zip" placeholder="Zip" style="text-align: left">
<br><br>
<textarea name="about" placeholder="About You" style="text-align: left; resize: both;" rows="5" cols="50"></textarea>
<br><br>
<div class="btn-group">
<button type="submit" class="btn btn-success dropdown-toggle" aria-haspopup="true" aria-expanded="false">Submit</button>
</div>
<br><br>
</form>
</center>
{{/if}}
Please let me know if you need additional info to help me solve this issue. Thanks!
you can use this code for node for editing the parameters , city,state,zip and about.
router.post('/add', function (req, res) {
var users = req.Collection;
var city = req.body.city;
var state = req.body.state;
var zip = req.body.zip;
var about = req.body.about;
var user_id = req.body.user_id;
if (city && state && ) {
users.findOneAndUpdate({_id: user_id}, {$set: {city: city, state: state, zip: zip, about:about}}, function (err, user) {
if (err) {
res.json({status: 0, message: err});
}
if (!user) {
res.json({status: 0, msg: "not found"});
} else {
res.json({status: 1, city: city, state: state, zip: zip, about:about, message: " edit success"});
}
})
} else {
res.json({status: 0, msg: "Invalid Fields"});
}
});

Sequelize ExpressJS Using Id for Post Method

I have a form that is being used to edit and update the record of a specific Id and I'm able to access the Id within my GET method for my route with req.params.annotationId, but when I try to use the POST version of getting a parameter with req.body.annotationId I get a value returned of NULL. I also tried to use req.params.annotationId and it returned the :annotationId placeholder for the route. Is this because the field is not present in the form? which would make sense because body-parser looks for values present in the fields?
This is the resulting query from the POST method:
Executing (default): SELECT `annotation_id` AS `annotationId`, `annotation_date` AS `annotationDate`,`user_id` AS `userId`, `createdAt`, `updatedAt`, `userUserId` FROM `annotation` AS `annotation` WHERE `annotation`.`user_id` = 1 AND `annotation`.`annotation_id` = NULL LIMIT 1;
Here is my route:
appRoutes.route('/edit/:annotationId')
.get(function(req, res){
console.log('This is the url path ' + req.originalUrl);
console.log(req.params.annotationId);
models.Annotation.find({
where: {
userId: req.user.user_id,
annotationId: req.params.annotationId
},attributes: ['annotationId', 'annotationDate']
}).then(function(annotation){
res.render('pages/annotation-edit.hbs',{
annotation: annotation,
user: req.user,
editMode: req.originalUrl
});
})
})
.post(function(req, res){
console.log("POST method triggered");
console.log(req.params.annotationId);
models.Annotation.find({
where: {
userId: req.user.user_id,
annotationId: req.body.annotationId
}
}).then(function(annotation){
if (annotation) {
console.log("Annotation exists");
annotation.update({
annotationDate: req.body.annotationDate,
userId: req.user.user_id
}).success(function() {
console.log("Annotation Updated");
});
}
})
});
Here is my annotation model:
module.exports = function(sequelize, DataTypes) {
var Annotation = sequelize.define('annotation', {
annotationId: {
type: DataTypes.INTEGER,
field: 'annotation_id',
autoIncrement: true,
primaryKey: true
},
annotationDate: {
type: DataTypes.DATE,
field: 'annotation_date'
},
userId: {
type: DataTypes.STRING,
field: 'user_id'
}
},
{
freezeTableName: true,
},
classMethods: {
associate: function(db) {
Annotation.belongsTo(db.User)
}
}
});
return Annotation;
}
Here is the form for the POST request:
<div class="row">
<div class="col-md-8 col-md-offset-2">
<div class="annotation-form">
<form action="/app/edit/:annotationId" method="post">
<div class="annotation-form-header">
<img class="user-image" src="http://placehold.it/80x80" alt="Generic placeholder image">
<label for="annotation-date">Annotation Date:</label>
<input type="date" name="annotationDate" id="annotation-form-date" value="{{annotation.annotationDate}}">
</div>
<button type="submit" id="create-annotation-button">Update Annotation</button>
</form>
req.body.annotationId with get annotationID from data in form like :
<form action="/app/edit" method="post">
<input name="annotationId" type="hidden" value="121313">
<div class="annotation-form-header">
<img class="user-image" src="http://placehold.it/80x80" alt="Generic placeholder image">
<label for="annotation-date">Annotation Date:</label>
<input type="date" name="annotationDate" id="annotation-form-date" value="{{annotation.annotationDate}}">
</div>
<button type="submit" id="create-annotation-button">Update Annotation</button>
</form>
```
req.params.annotationId get annotationID from URL : /edit/4465465
<form action="/app/edit/:annotationId" method="post"> <- invalid URL
The form should use the handlebars object to pass in the current Id selected like so,
<form action="/app/edit/{{annotation.annotationId}}" method="post">
<input name="annotationId" type="hidden" value="121313">
<div class="annotation-form-header">
<img class="user-image" src="http://placehold.it/80x80" alt="Generic placeholder image">
<label for="annotation-date">Annotation Date:</label>
<input type="date" name="annotationDate" id="annotation-form-date" value="{{annotation.annotationDate}}">
</div>
<button type="submit" id="create-annotation-button">Update Annotation</button>
</form>
The route should then be change from .find to .update:
.post(function(req, res){
console.log("POST method triggered");
console.log(req.params.annotationId);
models.Annotation.update({
annotationId: req.body.annotationId,
annotationDate: req.body.annotationDate,
},{where:{
userId: req.user.user_id,
annotationId: req.body.annotationId
}}).then(function(){
console.log("Annotation was Updated");
res.redirect('/app');
});
});

Resources