I am using express as my webserver for node and everything seems to be working correctly. The only problem I am encoutering is when I load a specific page ('/learn' route) 10 times repeatedly. Once I do this, express seems to stop working, although no error is logged to the console and nothing wrong is displayed on the page. It just keeps waiting for the host in the browser. What is weird is that the problem doesn't occur if I go from the page with the problem to another page, and then back again. I can repeat this as much as I want without error. Here is my route with the problem:
var bcrypt = require('bcrypt');
var pool = require('../database.js').pool;
module.exports = function(app) {
app.get('/learn', function(req, res, next) {
var query = 'SELECT * FROM questions INNER JOIN answers ON questions.questionID = answers.questionID';
pool.getConnection(function(err, connection) {
connection.query(query, function(err, rows) {
if (err) {
throw err;
}
var data = {
name: req.session.name,
problems: rows,
};
res.render('learn.html', data);
});
});
});
app.post('/learn/checkAnswer', function(req, res) {
//get posted form data
var questionID = req.body.questionID;
var selectedAnswer = req.body.selectedAnswer;
//query database
pool.getConnection(function(err, connection) {
var query = connection.query('SELECT correctAnswer FROM questions WHERE questionID = ?', questionID, function(err, rows) {
res.send({
correctAnswer: rows[0].correctAnswer
});
});
});
});
};
I'm not sure if this makes a difference, but I am using handlebars as my rendering engine instead of jade, as well as node-mysql for my database.
10 is the default size of the node-mysql pool. And since you're not ending the connections retrieved with pool.getConnection, the 11th request will wait indefinitely for a free connection.
Easy to fix:
connection.query(query, function(err, rows) {
connection.end(); // end the connection as soon as possible,
// so it's returned to the pool and can be reused.
if (err) ...
});
Related
I know this question have many duplicates, but I have already wasted too much time searching for the right solution.
First take a look at my Node.JS:
var express = require('express');
var app = express();
app.get('/', function (req, res) {
var sql = require("mssql");
// config for your database
var config = {
user: 'myuser',
password: 'mypass',
server: 'myip',
database: 'mydatabase'
};
sql.close();
// connect to your database
sql.connect(config, function (err) {
if (err) console.log(err);
var dataqu = '';
// create Request object
var request = new sql.Request();
// query to the database and get the records
request.query("select * from AR_Invoices", function (err, recordset) {
if (err) console.log(err)
res.json(recordset);
sql.close();
});
});
});
var server = app.listen(5000,'0.0.0.0', function () {
console.log('Server is running..');
});
This code runs fine, but the json result structure is like this :
{"recordsets":[[{"Tipe":"Invoices","InvoiceID":411891,"InvoiceNumber":"SR.1701.0001"}]],"recordset":[{"Tipe":"Invoices","InvoiceID":411891,"InvoiceNumber":"SR.1701.0001"}],"output":{},"rowsAffected":[1]}
I don't know why but for some reason the result is always resulting in duplicate.
And how to just select InvoiceID and InvoiceNumber ?
I already tested using recordset.InvoiceID or recordset[0].InvoiceID but all is always in vain, and the result always in duplicate.
Can anyone explain how to do this properly?
I want the final result became like this :
[
{ "InvoiceID":"1", "InvoiceNumber":"mynumber" }
]
For the future reference, i finally got how to do this here is my full code
var express = require('express');
var app = express();
var dateFormat = require('dateformat');
app.get('/', function (req, res) {
var sql = require("mssql");
// config for your database
var config = {
user: 'myuser',
password: 'mypassword',
server: 'myip',
database: 'mydb'
};
sql.close();
// connect to your database
sql.connect(config, function (err) {
if (err) console.log(err);
// create Request object
var request = new sql.Request();
// query to the database and get the records
request.query("select top 2 'Invoices' as Tipe,InvoiceID,InvoiceNumber,InvoiceDate,(select top 1DriverPicture from dbDigitalApp.dbo.tbdriver) as Blob from AR_Invoices", function (err, result) {
if (err) console.log(err)
var myarr = new Array();
for (var i = 0; i < result.recordset.length; ++i) {
var InvoiceNumber = result.recordset[i].InvoiceNumber;
var InvoiceDate = dateFormat(result.recordset[i].InvoiceDate, "dd mmmm yyyy");
var Blob = result.recordset[i].Blob;
myarr.push({'InvoiceNumber':InvoiceNumber,'InvoiceDate':InvoiceDate,'Blob':Buffer.from(Blob).toString('base64')});
}
res.json(myarr);
sql.close();
});
});
});
var server = app.listen(5000,'0.0.0.0', function () {
console.log('Server is running..');
});
and the result of above code is like this :
answers
with above code you can get specific field only and do whatever you want with those specific data, such as change date format or encode base64.
i don't know if this the cleanest way to do this since the node.js has its own function using res.json that can set all field of retrieved data without need to loop through it.
But at least here is my kind of solution, hope it will be helpful to there future people who wondering the same thing like me.
I'm using node and postgres, I'm new to writing async function, what I'm trying to do is a very simple query that will do a total count of records in the database, add one to it and return the result. The result will be visible before the DOM is generated. I don't know how to do this, since async function doesn't return value to callers (also probably I still have the synchronous mindset). Here's the function:
function generateRTA(callback){
var current_year = new Date().getFullYear();
const qry = `SELECT COUNT(date_part('year', updated_on))
FROM recruitment_process
WHERE date_part('year', updated_on) = $1;`
const value = [current_year]
pool.query(qry, value, (err, res) => {
if (err) {
console.log(err.stack)
} else {
var count = parseInt(res.rows[0].count) + 1
var rta_no = String(current_year) + '-' + count
callback(null, rta_no)
}
})
}
For the front-end I'm using pug with simple HTML form.
const rta_no = generateRTA(function (err, res){
if(err){
console.log(err)
}
else{
console.log(res)
}
})
app.get('/new_application', function(req, res){
res.render('new_application', {rta_number: rta_no})
});
I can see the rta_no in console.log but how do I pass it back to the DOM when the value is ready?
Based on the ajax call async response, it will update the div id "div1" when it gets the response from the Node js .
app.js
app.get("/webform", (req, res) => {
res.render("webform", {
title: "Render Web Form"
});
});
app.get("/new_application", (req, res) => {
// Connect to database.
var connection = getMySQLConnection();
connection.connect();
// Do the query to get data.
connection.query('SELECT count(1) as cnt FROM test ', function(err, rows, fields) {
var person;
if (err) {
res.status(500).json({"status_code": 500,"status_message": "internal server error"});
} else {
// Check if the result is found or not
if(rows.length==1) {
res.status(200).json({"count": rows[0].cnt});
} else {
// render not found page
res.status(404).json({"status_code":404, "status_message": "Not found"});
}
}
});
// Close connection
connection.end();
});
webform.pug - Via asynchronous call
html
head
script(src='https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js')
script.
$(document).ready(function(){
$.ajax({url: "/new_application", success: function(result){
$("#div1").html(result.count);
}});
});
body
div
Total count goes here :
#div1
value loading ...
That seems okay, I'm just not sure of this:
The result will be visible before the DOM is generated
This constraint defeats the purpose of async, as your DOM should wait for the returned value to be there. Instead of waiting for it you could just render the page and once the function returns and runs your callback update the value.
Also, perhaps it's worth having a look into promises
I'm trying to create web services using node.js from an sql server database,in the frontend when i call those 2 webservices simultaneously it throws an error Global connection already exists. Call sql.close() first .
Any Solution ?
var express = require('express');
var router = express.Router();
var sql = require("mssql");
router.get('/Plant/:server/:user/:password/:database', function(req, res, next) {
user = req.params.user;
password = req.params.password;
server = req.params.server;
database = req.params.database;
// config for your database
var config = {
user: user,
password: password,
server: server,
database:database
};
sql.connect(config, function (err) {
// create Request object
var request = new sql.Request();
// query to the database and get the records
request.query("SELECT distinct PlantName FROM MachineryStateTable"
, function (err, recordset) {
if (err) console.log(err)
else {
for(i=0;i<recordset.recordsets.length;i++) {
res.send(recordset.recordsets[i])
}
}
sql.close();
});
});
});
router.get('/Dep/:server/:user/:password/:database/:plantname', function(req, res, next) {
user = req.params.user;
password = req.params.password;
server = req.params.server;
database = req.params.database;
plantname = req.params.plantname;
// config for your database
var config = {
user: user,
password: password,
server: server,
database:database
};
sql.connect(config, function (err) {
// create Request object
var request = new sql.Request();
// query to the database and get the records
request.query("SELECT distinct DepName FROM MachineryStateTable where PlantName= '"+plantname+"'"
, function (err, recordset) {
if (err) console.log(err)
else {
for(i=0;i<recordset.recordsets.length;i++) {
res.send(recordset.recordsets[i])
}
sql.close();
}
});
});
});
module.exports = router;
You have to create a poolConnection
try this:
new sql.ConnectionPool(config).connect().then(pool => {
return pool.request().query("SELECT * FROM MyTable")
}).then(result => {
let rows = result.recordset
res.setHeader('Access-Control-Allow-Origin', '*')
res.status(200).json(rows);
sql.close();
}).catch(err => {
res.status(500).send({ message: `${err}`})
sql.close();
});
From the documentation, close method should be used on the connection, and not on the required module,
So should be used like
var connection = new sql.Connection({
user: '...',
password: '...',
server: 'localhost',
database: '...'
});
connection.close().
Also couple of suggestions,
1. putting res.send in a loop isn't a good idea, You could reply back the entire recordsets or do operations over it, store the resultant in a variable and send that back.
2. Try using promises, instead of callbacks, it would make the flow neater
You must use ConnectionPool.
Next function returns a recordset with my query results.
async function execute2(query) {
return new Promise((resolve, reject) => {
new sql.ConnectionPool(dbConfig).connect().then(pool => {
return pool.request().query(query)
}).then(result => {
resolve(result.recordset);
sql.close();
}).catch(err => {
reject(err)
sql.close();
});
});
}
Works fine in my code!
if this problem still bother you, then change the core api.
go to node_modules\mssql\lib\base.js
at line 1723, add below code before if condition
globalConnection = null
In case someone comes here trying to find out how to use SQL Server pool connection with parameters:
var executeQuery = function(res,query,parameters){
new sql.ConnectionPool(sqlConfig).connect().then(pool =>{
// create request object
var request = new sql.Request(pool);
// Add parameters
parameters.forEach(function(p) {
request.input(p.name, p.sqltype, p.value);
});
// query to the database
request.query(query,function(err,result){
res.send(result);
sql.close();
});
})
}
Don't read their documentation, I don't think it was written by someone that actually uses the library :) Also don't pay any attention to the names of things, a 'ConnectionPool' doesn't seem to actually be a connection pool of any sort. If you try and create more than one connection from a pool, you will get an error. This is the code that I eventually got working:
const sql = require('mssql');
let pool = new sql.ConnectionPool(config); // some object that lets you connect ONCE
let cnn = await pool.connect(); // create single allowed connection on this 'pool'
let result = await cnn.request().query(query);
console.log('result:', result);
cnn.close(); // close your connection
return result;
This code can be run multiple times in parallel and seems to create multiple connections and correctly close them.
I have an android game that has 40,000 users online. And each user send request to server every 5 second.
I write this code for test request:
const express = require('express')
const app = express()
const pg = require('pg')
const conString = 'postgres://postgres:123456#localhost/dbtest'
app.get('/', function (req, res, next) {
pg.connect(conString, function (err, client, done) {
if (err) {
return next(err)
}
client.query('SELECT name, age FROM users limit 1;', [], function (err, result) {
done()
if (err) {
return next(err)
}
res.json(result.rows)
})
})
})
app.listen(3000)
Demo
And for test this code with 40,000 requests I write this ajax code:
for (var i = 0; i < 40000; i++) {
var j = 1;
$.ajax({
url: "http://85.185.161.139:3001/",
success: function(reponse) {
var d = new Date();
console.log(j++, d.getHours() + ":" + d.getMinutes() + ":" + d.getSeconds());
}
});
}
SERVER detail(I know this is poor)
Questions:
this code (node js)only response 200 requests per second!
how can improve my code for increase number response per second?
this way(ajax) for simulate 40,000 online users is correct or not?
if i use socket is better or not?
You should use Divide&Conquer algorithm for solving such problems. Find the most resource inefficient operation and try to replace or reduce an amount of calls to it.
The main problem that I see here is that server open new connection to database on each request which possibly takes most of the time and resources.
I suggest to open connection when the server boots up and reuse it in requests.
const express = require('express')
const app = express()
const pg = require('pg')
const conString = 'postgres://postgres:123456#localhost/dbtest'
const pgClient
pg.connect(conString, function (err, client, done) {
if (err) {
throw err
}
pgClient = client
})
app.get('/', function (req, res, next) {
pgClient.query('SELECT name, age FROM users limit 1;', [], function (err, result) {
if (err) {
return next(err)
}
res.json(result.rows)
})
})
app.listen(3000)
For proper stress load testing better use specialized utilities such as ab from Apache. Finally, sockets are better for rapid, small data transfer but remember it has problems with scaling and in most cases became very inefficient at 10K+ simultaneous connections.
EDIT: As #robertklep pointed out, better use client pooling in this case, and retrieve client from pool.
I have a node.js application that uses a mongodb database that I've created. Within it, I have a simple collection named comments with the contents { "author": "me", "comment": "this is a comment" } when I call db.comments.find({}).
However, when I attempt to access this collection for display within a jade view I have, it times out after an incrediable amount of time. Console.log for the error object shows it's either a MongoError or connection was destroyed by application. The question I have is why this is happening? I have no errant while loops and connection parameteres seem to check out. Here's what I have to connect with, stored in app.js
var app = express();
var mongodb = require('mongodb'),
serverdb = new mongodb.Server('127.0.0.1', 27017, {}),
db = new mongodb.Db('acl', serverdb, {safe:true});
app.use(function(req,res,next){
req.db = db;
next();
});
and the code I have in the middleware file, stored as a js file in /routes
var express = require('express');
var router = express.Router();
/* GET home page. */
router.get('/', function(req, res) {
var db = req.db;
var collection = db.collection('comments');
collection.find().toArray(function(err, docs) {
console.log("Printing docs from Array");
if (err) {
console.log(err);
} else {
console.log(docs);
}
});
db.close();
});
module.exports = router;
Like #legalize said, its best to get a mongo connection pool going instead of opening and closing the connection on every request. Perhaps something like this SO answer
As far as why you are getting errors, its probably because your db.close() needs to be in the collection.find().toArray() callback because otherwise it'll start closing the connection before the query even happens.
Lastly, you need to render the template somewhere so the response gets sent back to the client.
Putting it all together, you probably want something like this:
router.get('/', function(req, res) {
var db = req.db;
var collection = db.collection('comments');
collection.find().toArray(function(err, docs) {
console.log("Printing docs from Array");
db.close();
if (err) {
console.log(err);
} else {
console.log(docs);
res.render( 'yourJadeTemplate', { docs : docs } );
}
});
});
(but you really don't want to be closing the connection for every request, especially because you aren't opening it for every request)
Oddly enough replacing this code
var mongodb = require('mongodb'),
serverdb = new mongodb.Server('127.0.0.1', 27017, {}),
db = new mongodb.Db('acl', serverdb, {safe:true});
with this
var db = require("mongojs").connect("localhost:27017/acl", ["comments"]);
made all the difference. No more timeouts. A bit of tweeking to get it to return data.