rest api using express.js and PostgreSQL - node.js

I have a script that has rest apis that gets data from a postgresql database and returns it back to the client. At the start, the script only uses the about 7mb of memory and the response time when making queries is very fast. However, as time passes by(about 1 day), the memory used by the script balloons to 170mb. And now, the queries takes more than 1 minute to respond. But when I restart the script, it is now again fast on its response. I am clueless as to why this happens. Can anybody shed light on this? Here is a portion of what my script looks like:
var port = process.env.PORT || 8000;
var router = express.Router();
router.get('/:id/from/:prevdate', function (req, res) {
var results = [];
var id = req.params.id;
var prevdate = req.params.prevdate;
pg.connect(connectionString, function (err, client, done) {
var query = client.query("some sql statement here", [id, prevdate]);
query.on('row', function (row) {
results.push(row);
});
query.on('end', function () {
client.end();
return res.json(results);
});
if (err) {
console.log(err);
}
});
});
router.get('/:id/getdata', function (req, res) {
var results = [];
var id = req.params.id;
pg.connect(connectionString, function (err, client, done) {
var query = client.query("some sql statement here", [id]);
query.on('row', function (row) {
results.push(row);
});
query.on('end', function () {
client.end();
return res.json(results);
});
if (err) {
console.log(err);
}
});
});
app.use('/restapitest', router);
app.listen(port);
console.log('Webservice started using port: ' + port);

You are mixing connection pooling (which uses done()) with creating single connections (which uses client.end()).
Try this:
query.on('end', function() {
done();
return res.json(results);
});
Also, since you are storing all results in memory anyway, there's no need to use events. So with proper error and connection handling, you could use this:
pg.connect(connectionString, function (err, client, done) {
var sendError = function(err) {
console.log(err);
return res.sendStatus(500);
};
if (err) return sendError(err);
client.query("some sql statement here", [id, prevdate], function(err, results) {
// Done with the client.
done();
// Handle any errors.
if (err) return sendError(err);
// Return result
return res.json(results);
});
});

Related

Cannot set headers after they are sent to clients in node.js

My code is not working . I am beginner and don't know my problem. Kindly help.I have seen one or two solution on stackoverflow but didnot get .
This is code.
app.post('/post',(request,response)=>{
var description=request.body.description;
var contact_number=request.body.contact_number;
var city=request.body.city;
var budget=request.body.budget;
var category=request.body.optradio;
var query=connection.query("insert into jobs(Jobs_id,Description,Category,City,Contact_number,Budget) values(?,?,?,?,?,?)",[null,description,category,city,contact_number,budget],function(err){
if(err)
console.log(err);
else
response.send("successful");
});
response.redirect('/data');
});
app.get('/data',function(request,response){
connection.query("SELECT * FROM jobs ORDER BY Jobs_id DESC",(err, rows,fields) => {
if(err) {
console.log(err);
}
else {
response.render('feed', {title : 'Jobs Details',
items: rows })
}
});
});
app.listen(3000);
This is the error
pp.post('/post', (request, response) => {
var description = request.body.description;
var contact_number = request.body.contact_number;
var city = request.body.city;
var budget = request.body.budget;
var category = request.body.optradio;
var query = connection.query("insert into jobs(Jobs_id,Description,Category,City,Contact_number,Budget) values(?,?,?,?,?,?)", [null, description, category, city, contact_number, budget],
function (err) {
if (err) {
console.log(err);
} else {
response.redirect('/data');
}
});
});
app.get('/data', function (request, response) {
connection.query("SELECT * FROM jobs ORDER BY Jobs_id DESC", (err, rows, fields) => {
if (err) {
console.log(err);
}
else {
response.render('feed', {
title: 'Jobs Details',
items: rows
})
}
});
});
app.listen(3000);
There can be only one response to single HTTP request. In your code, you are first trying to send response with
response.send("successful");
but this on its own doesn't break the flow of the function which means that if the condition is actually met then this will execute and the execution continues and finds another response, in this case
response.redirect('/data');
and it will try to send another response to the original http request but at this point it is already too late because one response has already been send.
To solve this issue in general, you can place return in front of any line of code that is closing the the connection (response.send, response.redirect, ...). That way, the function's execution is terminated at the first response, whichever it is.
So you could do something like
var query=connection.query("insert into jobs(Jobs_id,Description,Category,City,Contact_number,Budget) values(?,?,?,?,?,?)",[null,description,category,city,contact_number,budget],function(err){
if(err)
console.log(err);
else
return response.send("successful");
});
return response.redirect('/data');
});

Why Variable is undefined in nodejs express

I am using node js express and calling model from the controller.When I call model form controller and getting a result in result variable and print it in console.log(result) it's undefined.
Controller
var user_model=require('../models/user');
exports.get_user = function(req, res) {
var result = user_model.get_users();
console.log(result);
}
Model
var connection=require('../config/connection');
exports.get_users = function() {
connection.query('SELECT * FROM users', function(err, rows) {
if(err) {
retrun err;
}
return rows;
});
}
This is happening because you are consoling the result before the query has finished. Node is asynchronous. Unlike php node doesn't wait for the query to finish before going to the next line.
Use promise to handle async calls
// **Controller**
var user_model = require('../models/user');
exports.get_user = function (req, res) {
user_model.get_users().then((result) => {
console.log(result);
}).catch(err => console.log(err));
}
// **Model**
var connection = require('../config/connection');
exports.get_users = function () {
return new Promise((resolve, reject) => {
connection.query('SELECT * FROM users', function (err, rows) {
if (err) {
reject(err);
}
resolve(rows);
});
}
})
}

Nodejs + redis + displaying results on the browser

I am having trouble displaying the results that I retrieve from redis with the redis driver in nodejs.
I display an array that initially was a JSON, but it displays lots of "/n" between the elements and properties and I have spent hours trying to fix it but I did not succeed.
Any hint about how can I present the information in the browser without the "/n" characters?
JSON.stringify? I have try it and no way. util.inspect... I have try it. I know I am doing something wrong but I cannot find what.
My code goes like this:
app.get('/retrieve_from_redis_promise', function(req, res) {
client.on('connect', function() {
console.log('Connected to Redis succesfully');
});
var p = new Promise(function(res, reject) {
if (true) {
client.hgetall("redis_db_name", function(err, replies) {
res(replies)
// Object.keys(replies).forEach(key => {});
});
} else {
reject(Error("It broke"));
}
});
p.then(function(result) {
res.send(result); // "Stuff worked!"
}, function(err) {
console.log(err); // Error: "It broke"
});
});
Try
client.hgetall("redis_db_name", function(err, replies) {
Object.keys(replies).forEach(key => {
replies[key] = JSON.parese(replies[key]);
});
res(replies)
});

Fetch from multiple, separate, collections with Express and MongoDB

I have a site where i need some data from my Mongo data to be shown. My problem, however, is that i need data from two collections. Collections that are completely separate and have nothing to do with each other.
Right now i have this in my routes for my profile-page:
router.get('/profile', function(req, res,next) {
var resultArray = [];
mongo.connect(url, function(err, db) {
var cursor = db.collection('users').find();
cursor.forEach(function(doc, err) {
resultArray.push(doc);
}, function() {
db.close();
res.render('profile/index', {users: resultArray});
});
});
});
And this, of course, works perfectly fine. But how do i get a second db.collection('colors').find(); to be passed along to my template too?
I'm sure it's something trivial, and me just not quite having the full grasp of things, but yeah.. I'm stuck..
Use the async library which is best suited for this scenario. Where you need to run multiple tasks that do not depend on each other and when they all finish do something else, you should use async.parallel() method. The signature is async.parallel(tasks, callback), where tasks is an array of functions.
It will immediately run all the functions in parallel, wait for all of them to call their task callback, and finally when all tasks are complete it will run callback (the final callback).
The following example demonstrates how this could be adapted for your use case:
router.get('/profile', function(req, res, next) {
mongo.connect(url, function(err, db) {
var locals = {};
var tasks = [
// Load users
function(callback) {
db.collection('users').find({}).toArray(function(err, users) {
if (err) return callback(err);
locals.users = users;
callback();
});
},
// Load colors
function(callback) {
db.collection('colors').find({}).toArray(function(err, colors) {
if (err) return callback(err);
locals.colors = colors;
callback();
});
}
];
async.parallel(tasks, function(err) { //This function gets called after the two tasks have called their "task callbacks"
if (err) return next(err); //If an error occurred, let express handle it by calling the `next` function
// Here `locals` will be an object with `users` and `colors` keys
// Example: `locals = {users: [...], colors: [...]}`
db.close();
res.render('profile/index', locals);
});
});
});
Try this code:
router.get('/profile', function(req, res,next) {
var resultArray = {
users : [],
colors : []
};
mongo.connect(url, function(err, db) {
var cursor = db.collection('users').find();
cursor.forEach(function(doc, err) {
resultArray.users.push(doc);
}
var colors = db.collection('colors').find();
colors.forEach(function(doc,err){
resultArray.colors.push(doc);
}, function() {
db.close();
res.render('profile/index', {users: resultArray.users, colors: resultArray.colors});
});
});
});
Didn't have time to check it, but I'm pretty sure that it would work.

Node/Express function and callback are not breaking with return

I am creating a 'refresh data' function in Node and I cannot figure out where to place the callbacks and returns. The function continues to run. Below is a list of things the function should do. Could someone help out?
Check if a user has an api id in the local MongoDB
Call REST api with POST to receive token
Store token results in a MongoDB
Terminate function
./routes/index.js
router.post('/refresh', function(req, res) {
var refresh = require('../api/refresh');
refresh(req, function() { return console.log('Done'); });
});
../api/refresh.js
var callToken = require('./calltoken');
var User = require('../models/user'); // Mongoose Schema
module.exports = function(req, callback) {
User.findOne( {'username':req.body.username}, function(err, user) {
if(err) { console.log(err) }
if (user.api_id == 0) {
callToken.postToken(req.body.username, callback);
} else { // Do something else }
});
};
./calltoken.js
var request = require('request');
var Token = require('../models/token'); // Mongoose Schema
module.exports = {
postToken: function(user, callback) {
var send = {method:'POST', url:'address', formData:{name:user} };
request(send, function(err, res, body) {
if(err) { console.log(err) }
if (res.statusCode == 201) {
var newToken = new Token();
newToken.token = JSON.parse(body).access_token['token'];
newToken.save(function(err) {
if(err) { console.log(err) }
return callback();
});
}
});
}
};
I'm not an expert in Express but everywhere in you code in lines with if(err) { console.log(err) } you should stop execution (maybe of course not - up to you app) and return 400 or 500 to client. So it can be something like
if(err) {
console.log(err);
return callback(err); // NOTICE return here
}
On successful execution you should call return callback(null, result). Notice null as a first argument - it is according nodejs convention (error always goes as first argument).

Resources