Dynamically pick values from req.body based on database attributes - javascript

I am building an app usine Node/EJS/Mongo where the user is building a capability survey, and needs to set the desired level for each question. The form that they use to pick the levels has a series of selects that look like:
<select class="form-control col-sm-4" id="<%=capability.capabilityId%>" name="<%=capability.capabilityId%>">
<option value=1>Developing</option>
<option value=2>Intermediate</option>
<option value=3>Advanced</option>
<option value=4>Role Model</option>
</select>
When the user then submits this form, I want to update the assessment to load in these expected levels.
The schema for assessments in my mongodb looks like:
var assessmentSchema = new mongoose.Schema ({
title: String,
startDate: Date,
endDate: Date,
behaviours: [{
behaviourName: String,
behaviourId: String,
order: Number,
capabilities: [{
orderCap: Number,
capabilityId: String,
capabilityName: String,
capabilityDesc: String,
developing: String,
intermediate: String,
advanced: String,
roleModel: String,
expectedLevel: Number,
motivation1: String,
motivation2: String,
motivation3: String,
motivation4: String,
motivation5: String
}] //capabilities object
}],
targetEmployees:[{
type: mongoose.Schema.Types.ObjectId,
ref: "Users"
}] //behaviours object
});
What I am thinking is I want to loop through all the capabilities, find the entry in req.body that has a name that matches capabilityId, and then update desiredLevel. I just can't see how to make it work. My route code currently looks like:
router.put(':id/levels', function(req, res) {
Assessment.findById(req.params.id, function(err, foundAssessment) {
foundAssessment.behaviours.forEach(function(b) {
b.capabilities.forEach(function(c) {
c.expectedLevel = req.body.SOMETHINGHERE
});
});
foundAssessment.save(function(err) {
if (err) {
console.log(err);
req.flash("error", err.message);
res.redirect("back");
} else {
// Send json back to xhr request
res.json(foundAssessment);
}
});
});
});

You can read request body dynamic attributes like this:
req.body[variable];

Related

Friend Request System - Express, MongoDB, EJS

I want to create a social network thus allowing users to send and interact with frind requests. As of now I have created the register, log-in and "search for other users function".
When I find and select another user, I display their user-info and have created a "Add friend" button.
Can anyone help me in a direction of the creation of the "Add friend" option? I have looked around for some time now, and not been able to find the correct solution. Below I have attached my UserSchema and route for finding users:
//User Schema
const UserSchema = new mongoose.Schema({
firstName: {
type: String,
required: true
},
lastName: {
type: String,
required: true
},
password: {
type: String,
required: true
},
},{ collection: 'Users' });
//Get single user based on ID
router.get('/user/get:id', ensureAuthenticated, function (req, res) {
MongoClient.connect(DBUri,{useUnifiedTopology: true }, function (err, db) {
let dbo = db.db(DBName);
const query = {_id: objectId(req.params.id)}
dbo.collection("Users").find(query).toArray(function(err, resultTasks) {
if (err) throw err;
res.render('../View/findFriend', {
resultTasks: resultTasks
});
db.close();
});
});
});
You can add something like this in your user schema:
friends: [{ type : ObjectId, ref: 'User' }],
OR
friends: userSchema
Take the one which suits you.
What that will do is add an array to the user, Then you can store IDs of friends.(Who are other users, hence the ref: 'User')
Then, When you have to fetch users you can do:
User.find(<ID or whatever you have to find Users>).populate('friends')
Also, To push a new friend simply use: user.friends.push(newFriend._id)

Filtering a query using Node JS and MongoDB

I am new to MangoDB and Node JS. I have always worked on SQL databases and I do not know the syntax of MongoDB well. I wanna try to filter the array that I receive from a MongoDB database. I know that JavaScript has a .filter() function to filter just the results that contain a string. Is it best practice to get all the objects from MongoDB and filter in Node or do I let MongoDB do the filtering?
My Node.JS project is a back-end project using Node.JS and Express to do CRUD operations on a MongoDB database. In the request I send a parameter called 'equalTo' that contains the value that should be filtered on.
var router = express.Router();
var Plot = require("./models/plot");
...
router.get("/plots", (req, res) => {
let query = "" + req.query.equalTo;
Plot.find((err, plots) => {
if (err) {
res.send(err);
}
res.json(plots);
});
});
The filtering should be an OR filter where all results where either the name or the cropName should CONTAIN the value of the string. If it is possible I would also like the comparison to ignore uppercase's. Here is a schema for the Plot object:
const plotSchema = mongoose.Schema({
area: {
type: String,
required: true
},
comments: {
type: String,
required: true
},
cropGroupName: {
type: String,
required: true
},
cropName: {
type: String,
required: true
},
name: {
type: String,
required: true
},
plotId: {
type: Number,
required: true
},
coords: {
type: [],
required: true
},
}, {
collection: "plots"
});
The format is the following:
Plot.find({$or:[{name: "anyname"},{cropName:"othername"}]})
For further information you can read here https://docs.mongodb.com/manual/reference/operator/query/or/
You may replace the strings above in your case with equalTo.

How to display users on current page?

For example I have a page with url "/foo", and I need to display my authenticated users nicknames on this page. Is there any default node.js/passport function for this, or I need to add every user of this page to database and display it with websockets?
User schema:
var userSchema = new Schema({
email: {type: String, required: true, unique: true },
password: {type: String, required: true },
nickname: { type: String, default: 'User'},
createdAt: { type: Date, default: Date.now }
});
Check if user is logged in:
function isLoggedIn(req, res, next) {
if (req.isAuthenticated()) {
return next();
}
req.session.oldUrl = req.url;
res.redirect('/');
}
This is how I solved it in a service that hosts stories. I had to display the number of users and their names on the current story page. I wanted to keep the solution simple enough so I decided to use a simple table in SQL.
In an SQL table with a single column, I stored PAGE_{PAGEID}_USER_{USERID}.
For every page when fetched by the user I added an entry on this table and queried the table column with the regex PAGE_{PAGEID}_USER_(.*) with updatedAt less than 1 minute of the current time.
This gives you the IDs of the users on the current page in the past 1 minute.
PS: The correct way to do this would be to do this very same thing in a Wide Column Store

React POST request without form?

I am trying to familiarize myself with sending POST data, this time using React. In this instance, I am attempting to do it without a form.
My front-end React code specifically looks like so:
stockconfirmbuy: function(){
var stin = this.refs.stockpriceref.innerHTML;
var totalbuyval = stin * this.state.stockdnum;
return (<div>
<p>Are you sure you would like to buy {this.refs.stocknameref.innerHTML} stock at ${this.refs.stockpriceref.innerHTML} per share?</p>
<p>Select Amount:</p>
<input className="form-control" defaultValue="1" type="number" value={this.state.stockdum} onChange={this.changestocknum} />
<p>Your Total:</p>
<p>${totalbuyval}</p>
<div id="buttongroups">
<button className="btn btn-success" onClick={this.buyprocess}>Buy It</button>
<button className="btn btn-danger" onClick={this.cancelprocess}>Cancel</button>
</div>
</div>);
},
My initial stockdnum state value is 1, for clarity's sake.
Meanwhile, my schema is arranged like so:
var UserSchema = new Schema({
email: { type: String, unique: true, lowercase: true},
password: String,
icapital: {type: Number, default: 9001},
profile: {
name: { type: String, default: ''},
picture: { type: String, default: ''}
},
address: String,
history: [{
date: Date,
stocklabel: String,
stockname: String,
stocknumber: Number,
stockpaid: Number
}]
});
My attempt at coding the transaction into my routes/user.js page looks like so:
router.post('/profile', function(req, res, next) {
User.findOne({ _id: req.user._id }, function(err, user) {
if (err) return next(err);
if (req.body.stocklabel) user.history.stocklabel = req.body.stocklabel;
if (req.body.stockname) user.history.stockname = req.body.stockname;
user.history.date = Date();
if (req.body.stocknumber) user.history.stocknumber = req.body.stocknumber;
if (req.body.stockprice) user.history.stockprice = req.body.stockprice;
user.save(function(err) {
if (err) return next(err);
req.flash('success', 'Purchase sucessful');
return res.redirect('/profile');
});
});
});
First, I would like to make sure that my transaction lines up with the arrangement of my Schema.
Second, going back to my front-end React code, I am not sure how to take the relevant data from my React into my DB. I want the operation to run on {this.buyprocess}. However, since it is not a traditional input form, I am unsure how to turn it into a submit button that transfers these following pieces of info.
{this.refs.stockpriceref.innerHTML} repressents the stock label.
{this.state.stockdnum} represents the amount, or the stock number.
{totalbuyval} represents the total cost, or the stock price.
I am not sure what the code in the this.buyprocess function would look like.

Mongoose/Mongodb: Exclude fields from populated query data

I use the following mongoose query in a MEAN-environment to find and output a particular author and his corresponding books.
Author
.findOne({personcode: code})
.select('-_id')
.select('-__v')
.populate('bookids') //referencing to book documents in another collection (->array of bookids)
.select('-_id') //this doens't affect the data coming from the bookids-documents
.select('-__v') //this doens't affect the data coming from the bookids-documents
.exec(function (err, data) {
//foo
});
I would also like to exclude the "_id" and "__v" fields from the populated data coming from the external documents. How can that be achieved?
The second parameter of populate is a field selection string, so you can do this as:
Author
.findOne({personcode: code})
.select('-_id -__v')
.populate('bookids', '-_id -__v')
.exec(function (err, data) {
//foo
});
Note that you should combine your field selections into a single string.
Thanks JohnnyHK, and for object parameter this works:
Entity.populate({
path: 'bookids',
// some other properties
match: {
active: true
},
// some other properties
select: '-_id -__v' // <-- this is the way
}).then(...) // etc
To exclude individually
User.findOne({_id: userId}).select("-password")
To exclude using the schema
var userSchema = mongoose.Schema({
email: {
type: String,
required: true,
unique: true,
},
password: {
type: String,
required: true,
select: false,
},
});
or this will also work
db.collection.find({},{"field_req" : 1,"field_exclude":0});
I came searching for something slightly different. just in case someone needs same as me.
you can specify specific fields to auto-populate during creation of schema as shown below
const randomSchema = mongoose.Schema({
name: {type: String,trim: true},
username: {type: String,trim: true},
enemies: {
type: ObjectId,
ref: randomMongooseModel,
autopopulate:{
select: '-password -randonSensitiveField' // remove listed fields from selection
}
},
friends: {
type: ObjectId,
ref: randomMongooseModel,
autopopulate:{
select: '_id name email username' // select only listed fields
}
}
});
I am using mongoose-autopopulate plugin for this example

Categories