Effective way to get data that's needed on all pages - node.js

I'm using nodejs and express and I have a navigation menu that is built using data that is in mongodb currently I'm just making a call to the database to get a list of companies and passing that back inside each route. There doesn't seem to be a way to store this information in localstorage client side. So I"m wondering what is the most effective way to handle this situation. Sample of my code
admin.get('/', function(res, resp){
mongodb.connect(url, function(err, db){
var collection = db.collection('companies')
collection.find({}).toArray(function(err, companies){
res.render('adminview', {companies:companies})//once the page is rendered I would like to save the company list to localstorage.
})
})
})
admin.get('/:company', function(res, resp){
/* repeating code from above because I need this list */
mongodb.connect(url, function(err, db){
var collection = db.collection('companies')
collection.find({}).toArray(function(err, companies){
/* more code to do stuff to render the company page */
res.render('companyadminview', {companies:companies, company:company})
}) })
I could be going about this the wrong way I'm new to web development this feels wrong to me but can't figure out a different way.

So, first off you should be able to store it in localstorage or sessionstorage just fine, unless you're targeting browsers that don't support it.
That said, I think it's best not to, as the fact that you're storing it in the DB implies that it changes with enough frequency that you will get buggy clientside behavior if you cache it there for too long.
Instead, I'd just setup a middleware and attach it to the locals object on a per request basis, unless you want to do some kind of cache on the server:
app.use(function(req, res, next) {
mongodb.connect(url, function(err, db){
if (err) return next(err);
var collection = db.collection('companies')
collection.find({}).toArray(function(err, companies){
if (err) return next(err);
res.locals.companies = companies;
next();
});
});
});

Related

How to save the session

I have created a function here :
router.get('/restful',function(req,res,next){
var resultArray=[];
mongo.connect(url,function(err,db){
assert.equal(null,err);
var cursor=db.collection('users').find();
cursor.forEach(function(doc,err){
assert.equal(null,err);
resultArray.push(doc);
req.session.resultArray=resultArray;
},function(){
db.close();
res.render('restful',{items:resultArray});
});
});
});
I have created a method/restful. The "restful" is a page.
All I want is when I load this page, the resultArray gets displayed, but it's not displayed at the first load.
It's displaying after we navigate it for the second time. So the data is not being retrieved.
How can I solve this issue?
Please help me to find the solution.
I don't believe this is due to the nature of how sessions work in node.js, but you may want to reference: https://stormpath.com/blog/everything-you-ever-wanted-to-know-about-node-dot-js-sessions
I would move req.session.resultArray out of the forEach as there is no benefit to overwriting the session multiple times when you're already building the array for its value, you can just set it later after you've built the entire array.
This shouldn't be an issue with needing to invoke a redirect to view the new session data because we're not even technically messing with accessing a cookie or session (yet), we're using res.render() to make a variable items expose an internal variable for resultArray within our view. Although if you want to play with that you can use res.redirect('/restful') to invoke a redirect where data should already be initialized.
I would look at something like this
router.get('/restful', function( req, res, next ) {
var resultArray = [];
mongo.connect(url, function( err, db ) {
assert.equal(null, err);
var cursor = db.collection('users').find();
cursor.forEach(function(doc, err){
assert.equal(null, err);
resultArray.push(doc);
});
db.close();
});
req.session.resultArray = resultArray;
// this should contain your
// session data
console.log(resultArray);
res.render('restful', {items:resultArray});
next();
});
But I would like to note, the problem you are facing is not with session data not saving or being accessible so to speak, but rather that at the time of res.render() your resultArray does not appear to be built yet as you're only exposing this variable to your view.
I would play around with logging your resultArray and the answer should become clear to you.

perform a mongoose query in querystring

I'm trying to do a simple mongoose query using the query string.
This works
router.get('/', function(req,res) {
myModel.find({name:"test e"}, function(err,data){
if(err) console.log(err)
res.json(data);
});
});
This doesn't work (I get the whole collection)..
router.get('/', function(req,res) {
console.log(req.query.q)
myModel.find(req.query.q, function(err,data){
if(err) console.log(err)
res.json(data);
});
});
with this request
/api/myModel?q={name:"test e"}
I don't think it's an url encoding issue since I print the 'q' var and it looks fine server side.
Side question: if this isn't the standard mode, what's the RESTful standard way to query a db?
Edit for more general details:
I don't need a simple access by id or name like Ashley B suggests, I need a proper search engine for my db (the user, using a graphic web interface, have to be able to query each field separately, potentially)
Edit 2:
thanks to Blakes Seven I solved my initial problem, but if you know or use a better way to perform a complex query I would happy to discuss. Maybe I should expose anther resource "/api/seach"?
I think I can answer your first question by answering your second (side question).
Let's say you have a User model, normally you'd have an endpoint to get all users, like so:
router.get('/users', function(req, res) {
// find all users
users.find({}, function(err, data){
if(err) console.log(err)
res.json(data);
});
});
To find a specific user you then have an endpoint like so:
router.get('/users/:name', function(req, res) {
// get the user's name from the url and find that user
users.find({name: req.params.name}, function(err, data){
if(err) console.log(err)
res.json(data);
});
});
So rather than passing the whole query through the query string, you just find use a specific part. Allowing the users to directly access your data with their own queries makes it much much harder to secure.
I would recommend you to use some library to parse the querystrings to mongoDB queries. It would fix your problem and make your code better.
querymen would help you by transforming /myModel?q=test+e into {name: 'test e'}, giving you full control over the querystring schema.
var querymen = require('querymen')
// querymen.middleware() defines an express middleware with querystring schema
router.get('/', querymen.middleware({
q: {
type: String,
paths: ['name']
}
}), function(req, res) {
console.log(req.querymen.query) // {name: 'test e'}
myModel.find(req.querymen.query, function(err,data){
if(err) console.log(err)
res.json(data);
});
});
The proper query should look like this:
/api/myModels?name=test%20e
The myModals part is in plural.
Check here: How to design RESTful search/filtering?

Save to database on change, angular and node js

I'm converting an MS Access database to a webapp. I'm using Angular JS, Node JS with the express framework and MySQL as database.
In ms access you don't have any edit/save features. When you edit something, the database changes instantly. I like this. Feels smooth. So I want to have this the same way in the web app. My question is. Will there be any problems with this approach in my webbapp?
This is a piece of my node js code which updates the database with a restcall:
/*
Post /api/products/ HTTP/1.1
*/
exports.editProduct = function(req, res) {
console.log(req.body);
var post = [{title_en: req.body.title_en},req.params.id];
if (connection) {
connection.query("UPDATE products SET ? WHERE id = ?", post, function(err, rows, fields) {
if (err) throw err;
res.contentType('application/json');
res.write(JSON.stringify(rows));
res.end();
});
}
};
And on the client side I use the a the $resource object
$scope.save = function(){
$scope.product.$save(function(){
console.log('Save successfull);
});
};
And in the view. I simply have inputs with ng-change:
<input ng-model="product.title_en" ng-change="save()".
Will this work good in production mode with a couple hundred users? Is the chances of blocking/crashing etc?
The only thing I see is if (err) throw err;
if there is an error the server crash so change it with a json response with a 500 status.
By the way express has a build-in way to output json
It's better off to validate title_en and id
exports.editProduct = function(req, res) {
console.log(req.body);
var post = [{title_en: req.body.title_en},req.params.id];
if (connection) {
connection.query("UPDATE products SET ? WHERE id = ?", post, function(err, rows, fields) {
if (err) {
return res.json(500,{ error: 'Cannot update the product' });
}
res.json(200,rows);
});
}
an other thing try to use restangular instead of resource it's a lot of fun :)
};

What's the best practice for MongoDB connections on Node.js?

This is something that is a bit unclear to me (I'm just getting started with Node and Mongo), and it really concerns me because of server performance and strain (which I guess is another question, but I'll get to that at the end of the post).
So, assuming I'm writing an API with Node.js and Restify, where each API endpoint corresponds to a function, should I:
a) open the db connection and store it in a global var, and then just use that in every function?
Example:
// requires and so on leave me with a db var, assume {auto_reconnect: true}
function openDB() {
db.open(function(err, db) {
// skip err handling and so on
return db;
}
}
var myOpenDB = openDB(); // use myOpenDB in every other function I have
b) open the db connection and then just put everything in one giant closure?
Example:
// same as above
db.open(function(err, db) {
// do everything else here, for example:
server.get('/api/dosomething', function doSomething(req, res, next) { // (server is an instance of a Restify server)
// use the db object here and so on
});
}
c) open and close the db each time it is needed?
Example:
// again, same as above
server.get('/api/something', function doSomething(req, res, next) {
db.open(function(err, db) {
// do something
db.close();
});
});
server.post('/api/somethingelse', function doSomethingElse(req, res, next) {
db.open(function(err, db) {
// do something else
db.close();
});
});
This last one is what I would do out of intuition, but at the same time I don't feel entirely comfortable doing this. Doesn't it put too much strain on the Mongo server? Especially when (and I hope I do get to that) it gets hundreds — if not thousands — of calls like this?
Thank you in advance.
I like MongoJS a lot. It lets you use Mongo in a very similar way to the default command line and it's just a wrapper over the official Mongo driver. You only open the DB once and specify which collections you'll be using. You can even omit the collections if you run Node with --harmony-proxies.
var db = require('mongojs').connect('mydb', ['posts']);
server.get('/posts', function (req, res) {
db.posts.find(function (err, posts) {
res.send(JSON.stringify(posts));
});
});
Option A is not a great idea since there is no guarantee that the DB will be finished opening before an HTTP request is handled (granted this is very unlikely)
Option C is also not ideal since it needlessly opens and closes the DB connection
The way that I like to handle this is using deferreds/promises. There are a bunch of different promise libraries available for Node but the basic idea is to do something like this:
var promise = new Promise();
db.open(function(err, db) {
// handle err
promise.resolve(db);
});
server.get('/api/something', function doSomething(req, res, next) {
promise.then(function(db)
// do something
});
});
I believe Mongoose handles connections in a way that vaguely resembles this.

Proper Handling of fetch errors for Mongoose?

This is a pure best practice question. I am pretty new to Node and Mongoose. I absolutely love the technology and have been cranking away on a project to build a JSON-backed API for an app that I'm building.
I am finding that I am continuously repeating code when I fetch objects from my database. For example:
Playlist.findById(req.params.id, function(err,playlist){
if (err)
return res.json({error: "Error fetching playlist"});
else if (!playlist)
return res.json({error: "Error finding the playlist"});
//Actual code being performed on the playlist that I'm fetching
});
The error handling at the top of the function call is annoying because I have to repeat that code for every call to the database... or so I think.
I thought about using a callback like:
var fetchCallback = function(err,objOrDoc,callback){
//Handle the error messages
callback(objOrDoc);
};
However, this approach would mess up my sequential flow since I would have to define the callback function before I performed the fetch. So, if I had a lot of database queries chained together, I would have to place the callbacks in reverse order, which is far from ideal in a clean-coding perspective.
I'm wondering if anyone has run into this issue and has any best practices for cutting down on the repetition.
I'm also using the express framework, so if there's a helpful way to handle it in express, I'd be interested to know, too.
There are a couple interesting approaches you could try here.
At the most simple, you could simply have a function that loads up an object and handles the output in an error condition.
fetchResource = function(model, req, res, callback) {
model.findById(req.params.id, function(err, resource) {
if (err)
return res.json({error: "Error fetching " + model.toString()});
else if (!playlist)
return res.json({error: "Error finding the " + model.toString()});
callback(resource);
});
};
app.on('/playlists/1', function(req, res) {
fetchResource(Playlist, req, res, function(playlist) {
// code to deal with playlist.
});
});
That's still quite a bit of duplication, so I might try to move this out into a middleware.
Route Middleware
Routes may utilize route-specific middleware by passing one or more additional callbacks (or arrays) to the method. This feature is extremely useful for restricting access, loading data used by the route etc.
Now I haven't tested this and it's a bit hand-wavey (read: pseudocode), but I think it should serve as a decent example.
// assuming a URL of '/playlist/5' or '/user/10/edit', etc.
function loadResource(model) {
return function(req, res, next) {
model.findById(req.params.id, function(err, resource) {
if (err)
return res.json({error: "Error fetching " + model.toString()});
else if (!resource)
return res.json({error: "Error finding the " + model.toString()});
req.resource = resource;
next();
});
}
}
app.get('/playlist/:id', loadResource(Playlist), function(req, res) {
var playlist = req.resource;
...
});
app.get('/user/:id', loadResource(User), function(req, res) {
var user = req.resource;
...
});
The express source contains a pretty good example of this pattern, and the middleware section in the docs (specifically under 'Route Middleware') details it further.

Resources