Display to client only if collection exists on mongoDB Node JS - javascript

I have this schema model defined on Mongoose:
var mongoose = require("mongoose");
var IngredientSchema = new mongoose.Schema({
name:String,
number:Number,
exist:Boolean,
photoName:String
})
module.exports = mongoose.model("Ingredient", IngredientSchema);
And I want to display on a web page a different result depending on whether there is an Ingredient already created on database or not.
Here's what I tried so far (but it doesn't work):
<!-- Check if inventory is empty or not, and display accordingly -->
<% if ( ! ingredients) { %>
<p>Add you first ingredient to the inventory !!</p>
<% } else { %>
<% ingredients.forEach(function(ingredient) { %>
...
...
And here's my route:
// Index route
app.get("/inventory", function(req, res) {
Ingredient.find({}, function(err, allIngredients) {
if (err) {
console.log(err);
} else {
res.render("inventory", { ingredients:allIngredients });
}
})
})
Thank you very much for your help.

Just check the length of ingredients array:
<!-- Check if inventory is empty or not, and display accordingly -->
<% if (!ingredients.length) { %>
<p>Add you first ingredient to the inventory !!</p>
<% } else { %>
<% ingredients.forEach(function(ingredient) { %>
...
...

Related

JAVASCRIPT MongoDB delete specific object from array

I have got a nested array brought within a query from database, query brings the following:
{
_id: new ObjectId("623rf3f22275f399f88bb"),
first_name: 'Are',
last_name: 'You',
email: 'helping#stackoverflow.me',
password: '$2a$10$BSmezAjYkqU.234t65sT1pPOhg5jxosYrFzwjqXM3On3v.b7p46K1WS',
username: 'lcd1',
Messages: [
{
msgcontent: 'The user whatever said: whatsup.'
},
{
msgcontent: 'The user whatever said: whatsup.'
},
{
msgcontent: 'The user whatever said: whatsup.'
},
{
msgcontent: 'The user whatever said: whatsup.'
},
{
msgcontent: 'The user whatever said: whatsup.'
}
]
}
And I have a button for deleting in each of the brought iterations of a for loop on the page, how do I delete a specific message from the array using the button displayed from the iteration on the page?
I've got this displaying messages:
<% if (messages.length > 0) { %>
<% for (let nr = 1; nr <= messages.length; nr++) { %>
<div class="cardmsgpage">
<div class="displaymsg">Message <%= [nr] %> : <%= messages[nr-1].msgcontent %> </div>
<div class="sideways">
<form action="/deletemsg:id" method="POST">
<button class="msgpagebtn" type="submit"><img class="icon" src="/images/trash-can-solid.svg"></button>
</form>
</div>
</div>
<% } %>
and on the POST method I have:
app.post('/deletemsg', function (req, res) {
for (let nr = 0; nr <= messages.length; nr++) {
message = messages[nr];
}
users.findOne({}).then(result =>{
console.log(result);
users.deleteOne( { "Messages" : [messages[nr]] } );
console.log(result);
})
});
Can anyone tell me how I can delete only the message matching the button of the iteration that displayed it?
If I understood your concern correctly,
I think you are trying to say that you are displaying all the messages(as mentioned above in the problem) as Message i : <message content> and a delete button next to it, upon clicking which sends a POST request to the server to delete the message you've clicked on.
According to me, you can do one thing.....
When post request is made, it should be known to the handeler that which database record is to be modified(object id) and then inside of it which message is to be deleted.
To identify the message which should be deleted you can provide unique id to each of the message object inside your Messages property in database record or you can make a separate message schema and model and use it to store message in Messages array, then each message in Messages array will have unique id.
And then, we can use combination of the database record id(objectId) and the message id to delete the specific message from a specific database record.
Each message having unique id looks like...
{
_id: new ObjectId("623rf3f22275f399f88bb"),
first_name: 'Are',
last_name: 'You',
email: 'helping#stackoverflow.me',
password: '$2a$10$BSmezAjYkqU.234t65sT1pPOhg5jxosYrFzwjqXM3On3v.b7p46K1WS',
username: 'lcd1',
Messages: [
{
_id: <message-id>,
msgcontent: 'The user whatever said: whatsup.'
},
{
_id: <message-id>,
msgcontent: 'The user whatever said: whatsup.'
}
...........
]
}
Pass record's objectId and Messages array or whole object to the ejs file. Your action field of the form looks like /deletemsg/:record_id/:msg_id.
Inside your ejs file
// record_id is objectId of database record
<% if (messages.length > 0) { %>
<% for (let nr = 1; nr <= messages.length; nr++) { %>
<div class="cardmsgpage">
<div class="displaymsg">Message <%= [nr] %> : <%= messages[nr-1].msgcontent %> </div>
<div class="sideways">
<form action="/deletemsg/record_id/messages[nr-1]._id" method="POST">
<button class="msgpagebtn" type="submit"><img class="icon" src="/images/trash-can-solid.svg"></button>
</form>
</div>
</div>
<% } %>
Handle the POST request
app.post('/deletemsg/:record_id/:msg_id', function (req, res) {
users.findOne({_id: req.params.record_id }).then(result =>{
if(result){
console.log(result);
let messages = result.Messages;
// you have msg id, you have to delete that message
let idxToDelete = messages.findIndex(msg=>{
return msg._id === req.params.msg_id;
});
if(idxToDelete != -1)
messages.splice(idxToDelete, 1);
result.Messages = messages;
result.save().then(()=>{
console.log("Message deleted!!!");
}).catch(err=>{
console.log(err);
});
}
})
});
That's it......
Note:- you will have message and record schema like this below.....
const msg_schema = mongoose.Schema({
msgcontent: {type: String}
});
const record_schema = mongoose.Schema({
// everything same ......
// Messages array will have msg_schema types
Messages: [msg_schema]
});

Passing MongoDB Data into .ejs-Template with Node.js Express

I think i clicked myself through thousands of tutorials but i'm still stucked at this point: I want to render all the data, which my express-app is writing into mongodb at its start, into embedded javascript. I would like to have a simple table which is showing all the data from mongodb. It shall also always get the actualized Data when calling the route.
My first idea was, to save the data in an array. Pass it to the .ejs file. Create a table, iterate through my data-array and write it in. My problem is, that i can not write the data into an array after calling the find()-Function.
The model subscriber.js:
const mongoose = require('mongoose');
var uniqueValidator = require('mongoose-unique-validator');
var subscriberSchema = mongoose.Schema({
nr: Number,
mailIdent: {
type: String,
unique: true
},
from: String,
emails: {
type: String,
default: ''
},
text: String,
uLink: String,
anwalt: Boolean,
create_date:{
type: Date,
default: Date.now
}
});
subscriberSchema.plugin(uniqueValidator);
var Subscriber = module.exports = mongoose.model('Subscriber', subscriberSchema);
I'm really new to the topic and it feels like i'm just messing around. Please help
//get Subscriber
/*module.exports.getSubscribers = Subscriber.find(function(err, subs){
if(err) return console.error(err);
console.log(subs);
});
*/
module.exports.subscriber = Subscriber;
module.exports.getSubscriberByID = function(_id, callback){
Subscriber.findById(_id, callback);
};
module.exports.getSubscribers = function(){
var subscribers = Subscriber.find({});
return subscribers;
};
Then i want to pass it with my app.js to the index.ejs:
app.get('/', function(req, res){
var subs = Subscriber.getSubscribers().toArray();
console.log(subs);
res.render('index',{subs: subs} );
});
I know, that my .ejs still seems a little simple. But so far it shall be just functional:
<!DOCTYPE html>
<html>
<head>
<link href="/assets/styles.css" rel="stylesheet" type="text/css" />
</head>
<body>
<% include partials/nav.ejs %>
<h1>Welcome to the Database</h1>
<p>You won't find more Information than here!</p>
<p>Table</p>
<table>
<colgroup span="5" class="columns"></colgroup>
<tr>
<th>Nr</th>
<th>Name</th>
<th>Mail</th>
<th>uLink</th>
<th>Anwalt</th>
</tr>
<% for (var i = 0; i<subs.length; i++) { %>
<tr>
<td><%= subs[i].nr</td>
<td><%= subs[i].name</td>
<td><%= subs[i].email</td>
<td><%= subs[i].uLink</td>
<td><%= subs[i].anwalt</td>
</tr>
<% } %>
</table>
</body>
</html>
The following is from mongoose docs:
Query#find([criteria], [callback])
When no callback is passed, the
query is not executed. When the query is executed, the result will be
an array of documents.
You can use a callback just Like you do with getSubscriberByID function, here is an example:
subscriber.js:
...
module.exports.getSubscribers = function(cb){
Subscriber.find({}, cb);
};
app.js
app.get('/', function(req, res){
Subscriber.getSubscribers( function (err, subs) {
if (err) throw err;
// else render result
res.render('index', { subs: subs} );
});
});
here is ur app.js code..
app.get('/', (req, res) => {
// db.collection('story').aggregate([
// { $lookup:
// {
// from: 'story_content',
// localField: 'ObjectId("5a322e1130cb6225a086f37d")',
// foreignField: "5a322e1130cb6225a086f37d",
// as: 'joinstorydata'
// }
// }
// ]).toArray(function(err, res) {
// if (err) throw err;
// console.log("********************************************************")
// console.log(res);
// final=res;
// });
db.collection('bid_placement').find().toArray((err, docs2) => {
if (err) return console.log(err)
// renders index.ejs
lnames2 = [...new Set(docs2.map(a => a.bid_location))]
lnames2.sort();
res.render('index.ejs', {
//story12 : docs1 ,
//story_content: final,
storylocation : lnames2
});
});
});
and here is ur html code
<select name="Courses" id="Courses">
<% for(var i=0; i<storylocation.length; i++) {%>
<option value="<%= storylocation[i]%>"> <%= storylocation[i]%> </option>
<% } %>
</select>
you can use it like <%= storylocation[i].abc%> .. put you desire data instead of abc on each column of table...
It was driving me mad and finally i found out. I did not closed the Javascript in the .ejs file. That was definetly the most stupid misstake ever

Node.js cant log Class model data from Student model

I am having an issue here. I currently am making a school directory using node.js and MongoDB. I am in an app.post request and for some reason I can't get the name of the class being linked to the student to log to the console, but createdClass.name will print...
Here is the code...
app.post("/students/:id", function(req, res){
Student.findById(req.params.id, function(err, foundStudent){
if(err){
console.log(err);
} else {
Class.create(req.body.class, function(err, createdClass){
if(err){
console.log(err);
} else {
createdClass.student.id = foundStudent._id;
createdClass.student.name = foundStudent.name;
console.log(createdClass);
createdClass.save();
foundStudent.classes.push(createdClass);
console.log(foundStudent.classes[0].name);
foundStudent.save();
}
});
}
});
res.redirect("/students/" + req.params.id);
});
Also, here are my models...
STUDENT:
var mongoose = require("mongoose");
var studentSchema = new mongoose.Schema (
{
name: String,
classes: [
{
type: mongoose.Schema.Types.ObjectId,
ref: "Class"
}
],
grades: Array
}
);
module.exports = mongoose.model("Student", studentSchema);
CLASS:
var mongoose = require("mongoose");
var classSchema = new mongoose.Schema (
{
name: String,
student:
{
id:
{
type: mongoose.Schema.Types.ObjectId,
ref: "Student"
},
name: String
}
}
);
module.exports = mongoose.model("Class", classSchema);
Thank you in advance and please do let me know if there is anything I can add to make this easier to read.
Here is the page making the post request...
<div>
<h1>Student Profile</h1>
<h2>Name: <%=student.name%></h2>
<div>
<h3>Classes:
<form action="/students/<%= student._id %>" method="POST">
<%if(student.classes.length === 0){%>
<p>No classes linked to profile, please add class..</p>
<input type="text" name="class[name]" placeholder="Class name">
<% } else { %>
<% student.classes.forEach(function(course){ %>
<li><%= course.name %></li>
<% }); %>
<% } %>
</form>
</h3>
</div>
</div>
Class is a reserved word and can't be used for a variable

how to use app.locals inside app.get in express and parse

I am working on a parse application using express. I have an index file which shows the same information to the logged in users and public users except a login to public users and logout to logged in users. I am using app.locals to store a flag and logged-in user name but some how they are not getting stored.
My code for app.js is
// The homepage renders differently depending on whether user is logged in.
app.get('/', function(req, res) {
if(Parse.User.current()){
Parse.User.current().fetch().then(function(user) {
// Render the user profile information (e.g. email, phone, etc).
name = user.get('username');
});
app.locals({flag :true,name:name});
}else{
app.locals({flag:false, name:''});
}
// Render a public welcome page, with a link to the '/' endpoint.
var ProfessionalUsers = Parse.Object.extend("User");
var query = new Parse.Query(ProfessionalUsers);
query.limit(50);
query.equalTo("usertype", "Professional");
query.find().then(function(profs) {
res.render('index', {
title: "Popular Experts",
profs: profs,
});
});
});
The code I have written in index
<div class='navigation'>
<ul class='navigation-ul'>
<li><a href='/' class='search' id='searchLink' >Search</a></li>
<% if(flag){ %>
<li><a href='/dashboard' class='dashboard' id='dashboardLink' >Dashboard</a></li>
<% } %>
<li><a href='/howitworks' class='how-it-works' id='howItWorksLink'>How it Works</a></li>
<li><a href='/testimonials' class='testimonials' id='testimonialsLink' >Testimonials</a></li>
<li><a href='/faqs' class='faqs' id='faqsLink'>FAQs</a></li>
<% if(flag){ %>
<li><a href='/logout' class='logout' id='logoutLink'>Logout<span class='username'>(<%= name ? name : '' %>)</span></a></li>
<% }else{ %>
<li><a href='/login' class='login-signup' id='navLoginSignupLink'>Login/Signup</a></li>
<% } %>
</ul>
</div>
the code to show professionals
<p><%= title %></p>
<div class='professionals'>
<% for(var i=0;i<profs.length;i++) { %>
<div class='professional'>
<div class='picture-space' onclick = 'location.href = "/user/<%= profs[i].id %>"' style='cursor:pointer'>
<img src='images/default.jpg'/>
</div>
<div class='name-space'><%= profs[i].attributes.username %></div>
<div class='service-space'><%= profs[i].attributes.servicetype %></div>
<div class='linkedin-space'><a href='http://<%= profs[i].attributes.linkedin %>' target='_blank'>Linkedin Profile</a></div>
</div>
<% } %>
</div>
EDIT:
This is what I have done to fix this
// The homepage renders differently depending on whether user is logged in.
app.get('/', function(req, res) {
// Render a public welcome page, with a link to the '/' endpoint.
var ProfessionalUsers = Parse.Object.extend("User");
var query = new Parse.Query(ProfessionalUsers);
query.limit(50);
query.equalTo("usertype", "Professional");
query.find().then(function(profs) {
var user = Parse.User.current();
if(user){
user.fetch().then(function(user,error) {
res.render('index',{user:user.toJSON(),profs:profs,title:'Popular Experts'});
});
}else{
res.render('index', {
title: "Popular Experts",
profs: profs,
user:''
});
}
});
});
app.locals doesn't have access to the req, res objects. It is intended for non-dynamic data that doesn't change per request (like app-name, or something similar). I believe what you are after is res.locals (http://expressjs.com/api.html#res.locals)
I would suggest adding some middleware that does what you want.
You could load it just for your route. This will execute the middleware RIGHT before it executes the function you defined at that route:
function getUserInfo(req, res, next) {
var user_name = "adam"; //make some call here to get the user data
//make 'user_name' variable available in the view
res.locals.user_name = user_name;
next(); //go to the next 'middleware', which is the stuff you defined.
}
//add getUserInfo here as middleware that will run on the '/' route BEFORE your middleware runs. Yours will be executed when 'next()' is called from the middleware function.
app.get('/', getUserInfo, function(req, res) {

Sails.js - Creating a view to edit a model

I have a simple model as follows:
module.exports = {
attributes: {
firstName: 'STRING',
lastName: 'STRING',
contact: 'STRING',
email: 'STRING'
}
};
I already have an index action that displays all the humans. This is the corresponding view:
<h1>List of all humans</h1>
<ul>
<% _.each(humans, function(model) { %>
<li><%= model.firstName %> /// <%= model.lastName %> /// <%= model.contact %> /// <%= model.email %> <button id="<%=model.firstName %>"type="button">Edit</button> </li>
<% }) %>
</ul>
What I want to accomplish is that every time someone clicks on the EDIT button, to display a view containing all the information of that specific model (localhost:1337/human/edit/:id). How can I write my controller? How can I tell my controller that I want THAT specific model to be displayed and route it properly?
Thank you!
You should point browser to localhost:1337/human/edit/:id url, where :id is your particular model's id. For example
<ul>
<% _.each(humans, function(model) { %>
<li><%= model.firstName %> <button id="<%=model.firstName %>" type="button">Edit</button>
</li>
<% }) %>
</ul>
This will automatically execute Human.edit controller with id param set to particular model's id. You don't have to write any custom routes, this is default behaviour.
Example of Human/edit controller action:
edit: function(req, res) {
Human.findById( req.param('id') )
.done(function(err, human) {
if (err) {
return res.send(err, 500);
} else {
if (human.length) {
res.json(human[0]);
} else {
res.send('Human not found', 500);
}
}
});
}
Here I return model encoded as json in response, for simplicity, but you can use your view.
In addition, firstName property is not the best value to use as buttons id attribute, because it should be unique.

Categories