how to do a MongoDB query and use it in a partial view - node.js

I have a collection called events that I am currently using in my footer partial, however, I would like to show only the ones with a date greater than today. I have achieved this on mongo shell like this:
db.events.find({date: {$gte: new Date()}})
I don't understand how to use this query in footer partial where I am running a loop to show the events, I would like to save this query in a variable that I can use in the loop, and it would be visible in every page of the website as they all have the footer.
To be able to use this collection in every page I am using this code in my app.js
// passing courses to every EJS template
app.use(function (req, res, next) {
Event.find({}, function (err, allEvents) {
if (err) {
console.log(err);
res.locals.events = [];
next();
} else {
res.locals.events = allEvents;
next();
}
});
});
and this is where I am doing my loop in footer partial
<div id="event-footer" class="col-12 mt-4 mt-md-5 text-center col-md-4 text-md-left">
<div class="">
<h4 class="pb-1 pb-md-5">PROXIMOS EVENTOS</h4>
<% var count = 0; %>
<% events.forEach(function(event) { %>
<% if (count <= 2 ) { %>
<div class="eventDisplay text-center text-md-left">
<h6><%=moment(event.date).format('dddd, D MMMM, h:mm a')%></h6>
<p> <%= event.name %> </p>
</div>
<% } %>
<% count++; }); %>
</div>
</div>

Try this ...
Event.find({date: {$gte: new Date()}}, function (err, allEvents) { ...

Related

Iterate through a MongoDB object's data

I will start off with how my mongoDB data looks like:
_id : 5c5b450918cb2b121648ff7a
name : "dannondarko"
email : "dangilmail#gmail.com"
password : "$2a$10$3z5m1e9Pcfid72Q2GchCjeTD55/SsIxmtWr3I1ZiA.DX/KlpfTbdK"
date : 2019-02-06 20:35:21.973
__v : 0
posts : Array
0 : Object
note : "test for the user dannondarko"
date : "02/08/2019"
This is just a side project and most likely will never be live so don't worry about the security of me posting this data! As for how I am procession the code in my server code:
app.get('/:username', (req, res) => {
username = req.params.username.toLowerCase();
const collection = req.app.locals.collection;
collection.find({ name: username }).toArray(function (err, results) {
if (err) {
res.status(500).send("Error communicating with the DB.");
} else if (results.length > 0) {
console.log("Here are the results: " + results);
console.log({people: results});
res.status(200).render('profile', {posts: results, name: username});
} else {
next();
}
});
});
What I am doing with this code is say you head to the address bar '/dannondarko', it should find 'dannondarko' in the collection, which it does fine, and then the 'results' variable is the complete object that I posted above. What I am trying to do is just get the 'posts' data, such as the note and date.
The note and date is the only data I need, which will be sent to this .ejs file that should create a post (kind of like FB) that shows the users' notes and date of the post. Here is my .ejs file:
<h1 class="mt-4"><%= name %></h1>
<div class="container">
<br>
<% for(var i=0; i < posts.length; i++) { %>
<div class="container">
<label><%= posts[i].note %></label>
<div class="container">
<label><%= posts[i].date %></label>
</div>
</div>
<% } %>
</div>
I hope that's enough information. I believe my downfall is not knowing how to just extract the 'posts' array from MongoDB from a certain user and iterate through the objects and sending over the note and date to the .ejs.
The results is an array of documents and you render this array to ejs as posts. Now in your ejs file posts represent the array of documents, not the posts array. So if you want to loop through all results you should edit your code like this:
<% posts.forEach(post => { %>
<h1 class="mt-4"><%= post.name %></h1>
<div class="container">
<br>
<% post.posts.forEach(p => { %>
<div class="container">
<label><%= p.note %></label>
<div class="container">
<label><%= p.date %></label>
</div>
</div>
<% }) %>
</div>
<% }) %>
If i understand well your mongo model structure the above should help you.

Conditional operators in ejs

This might sound really easy. There is a very similar
answer but somehow my code is behaving abruptly and driving me crazy. I have spent last 4-5 hours on this. Any help would be great.
I am building a Socket.IO chat app using Node + Express + Passport. I want to compare the userId of the current user with that of other users connected. I want to show him all users except himself to chat with in Socket.IO.
Read comments on code for clarity :
users.js
app.get('/users', function (req, res) {
var connectedUsers = require('../app').chatUsers; // => This is an array of all logged in user and I am getting this all correctly.
if (req.isAuthenticated()) {
res.render('users', {
currentUser: req.user,
users: connectedUsers,
title: 'OnLineUsers'
});
}
});
users.ejs
<h3>CurrentUser : <%- currentUser.id %></h3> // => This Prints like **abcdefg**
<% for(var i = 0;i < users.length ; i++){ %>
<h3>UserID: <%- users[i].id %></h3> // => This also prints the same **abcdefg** if only one user is connected.
<% if( currentUser.id !== users[i].id){ %> // => But this Conditional Operator does not works and show the current user himself.
<ul>
<li>
<h3> <%= users[i].name %></h3>
<a href="/socket" id="chatRoomUrl">
<button type="submit" class="btn-success">Chat</button>
</a>
</li>
</ul>
<% } %>
<% } %>
Thanks in advance. If there is any silly mistake on my part, please excuse me for wasting your time.
Your code is fine. Maybe there is space in two property. Try :
currentUser.id.trim() !== users[i].id.trim()
Change your following line, notice the change:
<h3> <%= users[i].name %></h3>
to this:
<h3> <%- users[i].name %></h3>

Multiple mongoDB queries in one router.get method nodejs

I would like to have multiple queries in a single router method as follows in my index.js file,
router.get('/users', function(req, res) {
var db = req.db;
var users = db.get('users');
var col_name=req.query.colname;
var col_value=req.query.colvalue;
var query={};
query[col_name]=col_value;
console.log(col_name);
console.log(col_value);
console.log(query);
//using this i would like to populate my dropdown list
users.distinct('symbol',{limit: 10000},function(e, syms){
res.send('users', {
title: 'usersSym',
'usersSym': syms
});
});
// using this I would populate a table in html
users.find(query,{limit: 10000},function(e, docs){
res.render('users', {
title: 'Users',
'users': docs
});
});
});
And in my .ejs file I'm trying to do the following :
<html>
<head>
//drop down list populating with first query
<select id="selected" name="colvalue" >
<option value="">--Select--</option>
<% usersSym.forEach(function(usersym) { %>
<option value="<%= usersym.symbol %>"><%= usersym.symbol %></option>
<% }); %>
</select>
//Table populating with second query
<table >
<tr >
<th>Symbol</th>
<th>Order_id</th>
</tr>
<tr>
<% users.forEach(function(user) { %>
<td ><%= user.symbol %></td>
<td><%= user.order_id %></td>
</tr>
<% }); %>
</table>
</body>
</head>
</html>
But no luck. Wondering whether I'm going in right direction or not. If not please guide me in right way.
// 1st fetch symbol
users.distinct('symbol',{limit: 10000},function(e, syms){
// 2nd fetch [users]
users.find(query,{limit: 10000},function(e, docs){
res.render('users',
{
usersSym: syms,
users: docs
}
);
});
});
// P.S. do not forget to check on error on each callback
You can only send data back to the client once. One way would be to do all those DB queries in a sequence, and then send all the data. Another might be to do it your way, check the status of all DB queries, and if all are done, then send the data.

Sails.js flash message for user registration

I am following Sail.js tutorial from http://irlnathan.github.io/sailscasts/blog/2013/08/27/building-a-sails-application-ep4-handling-validation-errors-with-a-flash-message/
However I ran into a small problem. In the tutorial the author uses registration files inside his user folder and assigns routes in the user controller. He then sends validation errors using flash to the user.
However in my project, the registration files lies in the root folder and I assign the routes from the routes.js file like so
module.exports.routes = {
'/': {
view: 'index'
},
'/register': {
view: 'register'
}
};
Now the problem is to using flash to show users the validation errors while registration. I have used the following in the user controller (create) and it doesn't seem to work
if (err){
err.success = 0;
console.log(err);
req.session.flash = {
err: err
}
req.flash('error', req.session.flash);
return res.redirect('/register');
}
Any suggestions?
Sails.js version < 0.10.x based on his other thread output here
EDIT: See the Sails documentation here for more information - basically, since you're using static routing, no policies are applied before rendering the view, hence the flash policy isn't working. I'd recommend adding a register action in your UserController and just calling res.view() from there. There's also a StackOverflow post that discusses this, if you want more information.
I do have an alternative I developed for my own project that you can try out (also requires non-static routing).
In your api/policies folder, create a policy flash.js:
// flash.js policy
module.exports = function(req, res, next) {
res.locals.messages = { success: [], error: [], warning: [] };
if(!req.session.messages) {
req.session.messages = { success: [], error: [], warning: [] };
return next();
}
res.locals.messages = _.clone(req.session.messages);
// Clear flash
req.session.messages = { success: [], error: [], warning: [] };
return next();
};
This policy allows for three different flash types: success, warning, and error. It'll create an empty dictionary for each session and clear it on page loads.
I created a service FlashService.js in api/services to more easily flash messages:
// FlashService.js
module.exports = {
success: function(req, message) {
req.session.messages['success'].push(message);
},
warning: function(req, message) {
req.session.messages['warning'].push(message);
},
error: function(req, message) {
req.session.messages['error'].push(message);
}
}
Then, in your config/policies.js config file, make sure to assign the flash policy to the controller actions that you want to use flash with:
// config/policies.js
module.exports.policies = {
'*': [true, 'flash'],
'UserController': {
'register': ['flash'],
// any future actions that want flash
},
'AnotherController': {
'someAction': ['flash', 'somePolicy'],
}
}
To flash a message in your register action, just use FlashService.success(req, message). Alternatively, you can use FlashService.error and FlashService.warning, depending on how your UI styling works and how much you want to differentiate your flash messages.
In your view, you can put something like this:
<% if (messages && messages['error'].length > 0) { %>
<div class="alert alert-danger">
<% messages['error'].forEach(function(message) { %>
<%= message %>
<br>
<% }); %>
</div>
<br>
<% } %>
<% if (messages && messages['warning'].length > 0) { %>
<div class="alert alert-warning">
<% messages['warning'].forEach(function(message) { %>
<%= message %>
<br>
<% }); %>
</div>
<br>
<% } %>
<% if (messages && messages['success'].length > 0) { %>
<div class="alert alert-success">
<% messages['success'].forEach(function(message) { %>
<%= message %>
<br>
<% }); %>
</div>
<br>
<% } %>
Of course, you'll have to change the div classes to whatever classes are relevant to your UI.
In a normal mvc like rails or cakephp handling flash is something like this: $this->Flash->error('An Error Occurred Message'); then displayed it in an element.
In sails it should be simple as that.
In Controller: req.flash('error', 'An Error Occurred Message');
In View Partial: flash.ejs
<% if (req.session.flash) { %>
<% if (req.session.flash.success) { %>
<div data-alert class="alert-box success radius">
<%= req.flash('success') %>
×
</div>
<% } %>
<% if (req.session.flash.warning) { %>
<div data-alert class="alert-box warning radius">
<%= req.flash('warning') %>
×
</div>
<% } %>
<% if (req.session.flash.error) { %>
<div data-alert class="alert-box alert round">
<%= req.flash('error') %>
×
</div>
<% } %>
<% } %>
On Layout:
<%- partial('partials/flash') %>
Handling Error Message per field should be part in a Validation and Html Helper. (Like for example: https://gist.github.com/mikermcneil/8366092)
You can add this export:
module.exports = function flash(req, res, next) {
if (!req.session.flash) {
req.session.flash = {};
req.session.flash['success'] = [];
req.session.flash['warning'] = [];
}
next();
};
and then in the view:
<% if (req.session.flash['success'].length > 0) { %>
<div class="alert alert-success">
<%= req.session.flash['success'].pop() %>
</div>
<% } %>
<% if (req.session.flash['warning'].length > 0) { %>
<div class="alert alert-warning">
<%= req.session.flash['warning'].pop() %>
</div>
<% } %>
You can create messages in the controller like this:
req.session.flash['success'].push('Updated successfully');

MEAN correct way to refactor ejs express code

I've created a website with express and ejs, pulling JSON in from a file in a local file. I'd like to pass the data in from a mongo database and display with an Angular view. I have a good amount of knowledge in express, angular and mongo. Putting it all together and separating the express tasks from the angular tasks has me hung up a bit.
My app is working over in Heroku at http://healingcenter.herokuapp.com/services/ this is the page I'm unclear on how to separate the express and angular tasks.
It is currently set up in express, this was before I researched angular and the MEAN stack. below is the route config.
router.get('/services', function(req, res) {
var myServices = [];
var entireList = [];
entireList = appdata.services;
appdata.services.forEach(function(item) {
myServices = myServices.concat(item.title);
});
res.render('services', {
title: 'Services',
services: myServices,
list: entireList,
page: 'servicesList'
});
});
/* GET services detail page. */
router.get('/services/:servicesid', function(req, res) {
var myServices = [];
var entireList = [];
appdata.services.forEach(function(item){
if (item.shortname == req.params.servicesid){
entireList.push(item);
myServices = myServices.concat(item.title);
}
});
res.render('services', {
title: 'Services',
services: myServices,
list: entireList,
page: 'servicesDetail'
});
});
This is pulling in the same data.json file from the app.js file with this line of code.
app.locals.appdata = require('./data.json');
The page variable is the important part. An if else statement is customizing which data is brought in. That code is here:
<div class="services">
<% list.forEach(function(item){ %>
<article class="service group">
<% if (page!= 'servicesDetail') { %>
<h3><%= item.title %></h3>
<p><%- item.summary %></p>
more
<% }else{ %>
<a class="back" href="/services/#"><i class="fa fa-chevron-circle-left"></i> back</a>
<h3><%= item.title %></h3>
<p><%- item.description %></p>
<% } %>
</article>
<% }); %>
</div>

Resources