Iterate Mongodb Collection in pug/jade template - node.js

How do you pass a MongoDB collection to a .pug template?
I have this function that gets a mongodb collection named Test.
function get(req, res) {
mongo.GetSort({}, {state: 1, name: 1}, 'Test')
.then(function (list) {
res.send(list);
});
}
How would I pass this to a pug template? I try to
| console.log(Test) in the pug template but the object Test does not exist.
I have test.js and test.pug in my directory. I tried searching for my question but most results involved using Express.js. Thank you

I do not know where you get GetSort from? or what a Tailwater is? and you say without involving Express (because function get(req, res){ res.send(... sure looks like a signature express function, so you have me a little bit confused.)
Anyway, here is the simplest example I could come up with without any hint of express:
const compiledFunction = require('pug').compileFile('template.pug');
require('mongodb')
.connect('mongodb://localhost:27017/')
.then(mongo=>{
mongo
.db('somedb')
.collection('somecollection')
.find({})
.toArray()
.then(list=> {
// You just pass your data into the function
const html = compiledFunction({list: list});
console.log(html);
mongo.close();
});
});
And a template.pug along those lines:
html
head
title something
body
each item in list
div= item.title
The thing is, express does most templating under the hood. So using express would likely make it cleaner.
So if you have express, you want to follow the documentation: https://expressjs.com/en/guide/using-template-engines.html
app.set('view engine', 'pug'); //Tell express you want to use pug.
app.get('/', function (req, res) {
const list = ... //
res.render('template', { list : list });
})
This would do the same thing as the example above AND ALSO send the html to the clients browser (which is express' thing after all).
Did I miss something?

Related

Display Mongoose find in express

Being new to MongoDB and Mongoose, I feel really lost here.
After trying soooo many ways, I'm stuck with this: I can't figure out how Mongoose actually works, I went back to original state for clearer code reading, my tryouts are crashing node.JS.
I have this in the app.js that works:
PolyModel.find(null, function (err, poly) {
if (err) { throw err; }
console.log(poly);
});
Console shows good results in the shell, using a nice JSON format.
This line sends everything to the router
app.use('/', index);
My router:
var express = require('express');
var router = express.Router();
router.get('/', function(req, res, next) {
res.render('index', { title: 'Polygon grid', author: 'Author'});
});
module.exports = router;
My main question is: how do I get this poly value in the router / views?
I've red so much stuff and would like to learn the proper practices.
For information, my final goal would be to get this value into an Angular ng-repeat.
You are supposed to use module.exports function to expose the PolyModel schema on your js file that has all the routes. After that you can use it just above the res.render to get your data and then in the callback of the query use the res.render
If you don't want to run the query inside the routes javascript file you could implement a small express router middleware . Here is the documentation for it: https://expressjs.com/en/guide/using-middleware.html#middleware.router
Edit: Sadly I don't know how to use neither Jade template engine nor angular. I have only worked with EJS and jquery but I believe you can do something like this:
<script>
var something = #{poly};
</script>

Easiest way to pass variables to routes templates in Express?

I've just made an Node.js app modular by splitting up data models and routes into separate files.
My routes are exported by express.Router(). In these routes I would like to import queried values from my app.js to be rendered with the templates.
How would I in the easiest way save things lets say with app.locals or req.variableName?
Since the route using express.Router() ties it together with app.js, should I be using app.params() and somehow make these values accessible?
Using globals seems like a worse idea as I'm scaling up the app. I'm not sure if best practice would be saving values to the process environment either using app.locals.valueKey = key.someValue...
Big thanks in advance to anyone
If I understand the question correctly, you want to pass a value to a later middleware:
app.js:
// Let's say it's like this in this example
var express = require('express');
var app = express();
app.use(function (req, res, next) {
var user = User.findOne({ email: 'someValue' }, function (err, user) {
// Returning a document with the keys I'm interested in
req.user = { key1: value1, key2: value2... }; // add the user to the request object
next(); // tell express to execute the next middleware
});
});
// Here I include the route
require('./routes/public.js')(app); // I would recommend passing in the app object
/routes/public.js:
module.export = function(app) {
app.get('/', function(req, res) {
// Serving Home Page (where I want to pass in the values)
router.get('/', function (req, res) {
// Passing in the values for Swig to render
var user = req.user; // this is the object you set in the earlier middleware (in app.js)
res.render('index.html', { pagename: user.key2, ... });
});
});
});

Express Routes in Parse Cloud Code Module

I am using parse.com cloud code with express to setup my routes. I have done this in the past with node, and I have my routes in separate files. So, in node I do
app.js
express = require("express");
app = exports.app = express();
require("./routes/js/account");
account.js
app = module.parent.exports.app;
app.get("/api/account/twitter", passport.authenticate("twitter"));
All the examples on parses site https://parse.com/docs/cloud_code_guide#webapp show this being done as follows.
app.js
var express = require('express');
var app = express();
app.get('/hello', function(req, res) {
res.render('hello', { message: 'Congrats, you just set up your app!' });
});
So, I would like to change the bottom to include a routes folder with separate routes files, but am not sure how to do this in parse.
I know this post is a little old, but I just wanted to post a solution for anyone still looking to get this to work.
What you need to do, is create your route file, I keep them in 'routes' forlder, for example <my_app_dir>/cloud/routes/user.js
Inside user.js you will have something that looks like this:
module.exports = function(app) {
app.get("/users/login", function(req, res) {
.. do your custom logic here ..
});
app.get("/users/logout", function(req, res) {
.. do your custom logic here ..
});
}
Then, in app.js you just include your file, but remember that you need to append cloud to the path, and pass the reference to your app instance:
require('cloud/routes/user')(app);
Also, remember that express evaluates routes in order, so you should take that into consideration when importing several route files.
I'm using a different method, have the routes in app.js, but you can probably include them in file if you prefer. Take a look at the example app,
anyblog on github
The way it works:
Set up a controller:
// Controller code in separate files.
var postsController = require('cloud/controllers/posts.js');
Add the controller route
// Show all posts on homepage
app.get('/', postsController.index);
// RESTful routes for the blog post object.
app.get('/posts', postsController.index);
app.get('/posts/new', postsController.new);
And then in posts.js, you can use exports, ex.
var Post = Parse.Object.extend('Post');
// Display all posts.
exports.index = function(req, res) {
var query = new Parse.Query(Post);
query.descending('createdAt');
query.find().then(function(results) {
res.render('posts/index', {
posts: results
});
},
function() {
res.send(500, 'Failed loading posts');
});
};
// Display a form for creating a new post.
exports.new = function(req, res) {
res.render('posts/new', {});
};
Pass the app reference to the post controller, and add the routes from there

Returning/getting object from a module in nodejs mongodb

I am working on a nodejs app.
Folder structure is
app
app.js
package.json
../model/schema.js
../controller/controller.js
../views
All the logic is in controller.js while app.js performing routing itself....
I want to know how to get/return data(object) from controller.js to app.js.
I am using 'return' to send mongodb document from controller to app but its undefined.
Heres code of app.js..i have removed unneccessary code
var express = require('express'),
app = express.createServer(express.logger()),
io = require('socket.io').listen(app),
routes = require('./routes');
var controller=require('./controller/controller');
var model=require('./model/schema');
app.get("/", function(req, res) {
res.render("chatroom.html");
});
io.sockets.on('connection', function (socket) {
socket.on('login',function(user)
{
var onliner=controller.loginUser(user);
console.log("Onlinersss: ",onliner);
});
socket.on('registerUser',function(user){
controller.registerUser(user);
});
});
Heres controller.js code:
var model=require('../model/schema');
exports.loginUser=function(user)
{
model.registerUser.findOne({uname:user.uname,pass:user.pass},function(err,doc){
if(!err){
console.log("Here loggedin: ",doc);
return doc;
}
else
console.log("Invalid username or password");
});
};
I've just pushed a project to GitHub that uses pretty much the same libraries and RethinkDB as the database (very similar to MongoDB). Basically you need to pass callbacks to your controller and have them invoked with the data retrieved from the DB. Take a look at app.js and lib/db.js in the linked project.
JavaScript (and therefore node.js) is asynchronous. When you 'return doc' the anonymous function defined at function(err, doc) is returned... not the function loginUser that you are trying to get data from.
loginUser returns immediately, and it returns undefined (since you don't specify anything else). To see what I mean, put 'return true;' as the last line in loginUser and you'll notice that you get the value back of 'true.'
However, you don't want to return a value. You want to callback with a value. That's beyond the scope of a stackoverflow answer, so here is a good resource:
http://bjouhier.wordpress.com/2011/01/09/asynchronous-javascript-the-tale-of-harry/

Node.js Express routing with MongoDB

Good afternoon,
I recently started working with Node.js + Express + MongoDB.
I set up a simple app containing :
/**
* Module dependencies.
*/
var express = require('express')
, routes = require('./routes')
, mongoose = require('mongoose')
, models = require('./models')
, Document
, db;
// lots of conf ...
models.defineModels(mongoose, function() {
app.Document = Document = mongoose.model('Document');
db = mongoose.connect(app.set('db-uri'));
})
// Routes
app.get('/', routes.home);
app.get('/documents.:format?', routes.list);
// classical end of app.js
I also have a corresponding 'index.js' file within a 'routes' folder, containing:
exports.home = function(req, res){
res.render('index', { title: 'Indx' })
};
exports.list = function(req, res){
Document.find().all(function(documents) {
switch (req.params.format) {
case 'json':
res.send(documents.map(function(d) {
return d.__doc;
}));
break;
default:
res.render('index', { title: 'Indx' });
}
});
};
The routing part is OK, meaning that when I point my browser to localhost:3000, I see the (Jade-template generated) 'index' view. When I point to localhost:3000/documents, the routing works OK, and the code is trying to serve the 'list' part of my 'index.js' route. However, I was hoping that the 'Document' mongoose model I created in the main app would be recognized within 'index.js', but this is clearly not the case as I keep getting the following error :
Express
500 ReferenceError: Document is not defined
at C:\PERSO\DEV\indxjs\routes\index.js:23:2
at callbacks (C:\PERSO\DEV\indxjs\node_modules\express\lib\router\index.js:272:11)
at param (C:\PERSO\DEV\indxjs\node_modules\express\lib\router\index.js:246:11)
at param (C:\PERSO\DEV\indxjs\node_modules\express\lib\router\index.js:243:11)
at pass (C:\PERSO\DEV\indxjs\node_modules\express\lib\router\index.js:253:5)
at Router._dispatch (C:\PERSO\DEV\indxjs\node_modules\express\lib\router\index.js:280:4)
at Object.handle (C:\PERSO\DEV\indxjs\node_modules\express\lib\router\index.js:45:10)
at next (C:\PERSO\DEV\indxjs\node_modules\express\node_modules\connect\lib\http.js:204:15)
at Object.methodOverride [as handle] (C:\PERSO\DEV\indxjs\node_modules\express\node_modules\connect\lib\middleware\methodOverride.js:35:5)
at next (C:\PERSO\DEV\indxjs\node_modules\express\node_modules\connect\lib\http.js:204:15)
I could obviously define my routing from within the 'app.js' with something like :
app.get('/documents.:format?', loadUser, function(req, res) {
// ...
}
But can anyone see a way of talking with mongoose while retaining the elegant './routes/index.js' separation from the 'app.js' ?
Thanks a lot
EDIT : following kind answer from Wes, I added the following code to 'index.js':
var Document;
function defineRoutes(mongoose, fn) {
Document = mongoose.model('Document');
fn();
}
exports.defineRoutes = defineRoutes;
// then the same as in initial post
And I enclosed the routing definitions within this function in 'app.js' :
routes.defineRoutes(mongoose, function() {
app.get('/', routes.home);
app.get('/documents.:format?', routes.list);
})
Everything is ok when I point to localhost:3000, but when I point to /documents, the browser keeps loading, loading ...
Thanks to Wes Johnson, I found my way out. I was blindly following a dated tutorial, which used deprecated methods from MongoDb. Below is the code snippet I finally used to implement the 'list documents' feature:
exports.list = function(req, res){
Document.find({},function(err, documents) {
switch (req.params.format) {
case 'json':
res.send(documents.map(function(d) {
return d.toObject();
}));
break;
default:
res.render('index', { title: 'Indx' });
}
});
};
Once again, thanks Wes !
Node modules are self-contained in terms of variable scope. Your Document object is not accessible from index.js as you mention. You need to pass this along to your routes logic, or pass along mongoose itself.
require calls are cached for the most part, so requiring mongoose in your index.js file and getting an instance of Document there is one option.
Since you don't really use Document in your app.js, you could always move the db configuration to another module and export the important references back to the scripts that need them.

Resources