Nodejs MySQL connection timeout - node.js

When I run the application, It shows me Database is connected!
db.js
var mysql = require('mysql');
var settings = require('./config');
var db;
var exports = {};
exports.connectdb = function () {
db = mysql.createConnection(settings.Database);
db.connect(function(err){
console.log('connecting');
if(!err) {
console.log('Database is connected!');
return db;
} else {
console.log('Error connecting database!'+err);
return null;
}
});
};
module.exports = exports;
but when i am trying to connect DB from user.js it shows me connection is null / TypeError: Cannot read property 'query' of undefined.
code block from user.js
var exports = {};
var dbcon = require('../config/db.js');
var dbconn = dbcon.connectdb();
exports.login = function(email,password) {
var userdetails = { name:email, password:password};
var dbconn = dbcon.connectdb();
if ( dbconn == null ) console.log('still nul');
dbconn.query("SELECT * FROM users where email = '"+email+"' and password = '"+password +"'", function (err, result) {
if(err)
{
console.log(result[0]+' err');
return null;
}
});
};
module.exports = exports;

Node.js is asynchronous by nature. You are trying to use it in a synchronous fashion. To make this work, you must use the callback pattern. Below is an example:
db.js
var mysql = require('mysql');
var settings = require('./config');
var exports = {};
exports.connectdb = function (callback) {
var db = mysql.createConnection(settings.Database);
db.connect(function(err){
callback(err,db);
});
};
module.exports = exports;
user.js
var exports = {};
var dbcon = require('../config/db.js');
exports.login = function(email,password) {
var userdetails = { name:email, password:password};
dbcon.connectdb(function(err, dbconn){
if ( err) //handle error
dbconn.query("SELECT * FROM users where email = '"+email+"' and password = '"+password +"'", function (err, result) {
if(err)
{
console.log(result[0]+' err');
}
});
});
};
module.exports = exports;
From the code above you can see how the connectdb function accepts a function callback. When the database is connected the code will execute that callback to send the results. In the user.js file, you can now pass a callback function and use the results it gives you (the db). You can find more info about Node.js' asynchronous nature here. Basically, asynchronous code uses callbacks and synchronous code uses return statements. Returning values from asynchronous functions will most always yield null results as asynchronous callbacks will always fire "sometime" after the function is called.

Related

How to return data from a method that uses async functions?

I'm pretty new to using Express.js and I have an issue returning the data from the database query. The goal is to get user info from the table as JSON inside userController but only thing I get is undefined. I tried many different things but can't get my head around how to return the value from the method.
db.js
const mysql = require('mysql2');
var con = mysql.createPool({
//db data here
});
module.exports = con;
userController.js
var User = require("../models/userModel");
exports.registerUser = function(req, res){
if(req.method == 'POST'){
var username = req.body.username;
var email = req.body.email;
//doing checks
var u1 = new User(username, email);
console.log(u1.getInfo());
}
}
userModel.js
const db = require('../config/db');
module.exports = class User{
//constructor here
getInfo(){
try{
var query = "SELECT * FROM users";
db.query(query, function(err, data){
return JSON.stringify(data);
});
}
catch(err){
return err;
}
}
}
You are getting undefined because the query need to wait the answer, and when you call getInfo(), the return JSON.stringify(data); are only execute when the query have the data.
You can use promise warper, because you need to wait to the database response. To use promises mysql2 have this package: const mysql = require('mysql2/promise');
Make your getInfo() function asynchronous
async getInfo(){
try{
const res = await db.execute('SELECT * FROM users');
return res;
}
catch(err){
return err;
}
}
Then you can call the function with await:
exports.registerUser = async function(req, res){
if(req.method == 'POST'){
var username = req.body.username;
var email = req.body.email;
//doing checks
var u1 = new User(username, email);
console.log(await u1.getInfo());
}
I cant test the code now, but it should work

async await is not executing functions sequentially in express nodejs

I want to run 3 database query then render the 3 result objects to view, so I used async await to run queries first but seems its not waiting/working, always sending null objects to view before running queries. Cant find where I went wrong, I am using nodejs 12.16.1, not sure if its es6 supporting issue or sth else.
var express = require('express');
var router = express.Router();
var reviewModel = require.main.require('./models/review-model');
var propertyModel = require.main.require('./models/property-model');
router.get('/', async function(req, res){
try{
req.cookies['username'] == null ? loginCookie = null : loginCookie = req.cookies['username'];
var getPromoteInfo = await propertyModel.getPromoteInfo(function(result){
if(result!=null) return result;
});
var getPromoteReview = await reviewModel.getPromoteReview(function(result2){
if(result2!=null) return result2;
});
var getLatest3reviews = await reviewModel.getLatest3reviews(function(result3){
if(result3!=null) return result3;
});
res.render('index', {property:getPromoteInfo, rating:getPromoteReview, testimonials:getLatest3reviews, loginCookie});
}
catch(err){console.log(err);}
});
module.exports = router;
Model code:
var db = require('./db');
module.exports = {
getPromoteInfo: function(callback){
var sql = "select * from property where promote_status = 1;";
db.getResult(sql, null, function(result){
if(result){
callback(result);
}else{
callback(null);
}
});
}
}
You're using await on a function that does not return a Promise resulting in an undefined value. So in order for async/await to work, you could rewrite getPromoteInfo as follows:
var db = require('./db');
module.exports = {
getPromoteInfo: function(){
return new Promise( (resolve, reject) => {
var sql = "select * from property where promote_status = 1;";
db.getResult(sql, null, function(result){
if(result){
resolve(result);
}else{
// you can decide whether to reject or not if no records were found
reject();
}
});
});
}
}
In your express-handler you can then simply await this function call, without passing a callback:
const getPromoteInfo = await propertyModel.getPromoteInfo();
Note that you can check if your db-client/library supports promises out of the box - then you would not have to wrap your functions manually in a promise.

NodeJs - Imported variable is undefined

Consider this code snippet below which is in the A.js file.
const connection = {};
mongo_cli.connect(url, (err, db) => {
...
connection['con'] = db;
});
module.exports = {
mongo:{
connection: connection['con'];
}
}
I do this const database = require('./A').mongo.connection; in B.js. A and B js files are in the same directory.
Why database variable in B file is undefined ?
That's because connection['con'] = db is in the execution context of the connect function callback. If you access connection['con'] from outside you're likely to get undefined. I suggest you to use Mongoose for such implementations. Here is a simple example:
const mongoose = require('mongoose');
const url = "your_mongodb_url";
const connect = mongoose.connect(url, {
useNewUrlParser: true
});
connect.then((db) => {
console.log('Database Connected');
}, (err) => {
console.log(err);
});
U won't get undefined if the connection succeeded. so for handling that , you can try something like this.
const connection = {};
connection['con'] = null;
mongo_cli.connect(url, (err, db) => {
...
connection['con'] = db;
});
module.exports = {
mongo:{
connection: connection['con']; // if connection failed then connection['con'] will be null.
}
}
This is a callback function:
(err, db) => {
…
connection['con'] = db;
}
It might get executed after the code that reads the database variable in B.js.

Mocking connection pool and test url param using sinon?

I am doing a RESTful api using node.js,
Unit Testing using mocha, sinon, chai.
DB using ibm DB2.
Problem:
I am trying to a unit test on the getNews method.
I know the correct way of doing a unit test is not to access the database. So I am trying not to access the database.
Q1:
However, how do I do a mock on pool.open(connString, function (err, db) to return a fake result, assuming that I created the json result.
Assuming that my newsId that I want to get is 999.
Q2:
How do it ensure that the newsId i passed in is 999 and not another value?
Codes:
These are files that are already running correctly.
newsRest.js:
module.exports = (app) => {
const controller = require('../controller/newsController');
app.route('news/:newsId').get(controller.getNews);
};
newsController.js:
'use strict';
//imports
var connectionString = require('../common/ibmdb2Pool').connectionString;
var connString = connectionString();
var initPool = require('../common/ibmdb2Pool').initPool;
var pool = initPool();
const query = require('../db/query');
/*
* Restful API starts here
* */
//get news by id
exports.getNews = (req, res) => {
//get from request
const newsId = req.params.newsId;
const params = [newsId];
pool.open(connString, function (err, db) {
if (err) {
return console.log(err);
}
db.query(query.sqlSelect, params, function (error, result, info) {
if (error) {
console.log(error);
return false;
}
res.status(200).json({
result: result
});
});
});
};
ibmdb2Pool.js
'use strict';
//imports
require('dotenv').config();
var Pool = require("ibm_db").Pool;
// access the environment variables for this environment
var connString = process.env.CONNSTRING;
//variables
const minPoolSize = 20;
const maxPoolSize = 100;
//return connection string from environment file.
exports.connectionString = function () {
return connString;
};
//init the db pool with a min and max size
exports.initPool = function () {
var pool = new Pool();
var ret = pool.init(minPoolSize, connString);
if(ret !== true) {
console.log("Cannot init pool. " + ret);
}
pool.setMaxPoolSize(maxPoolSize);
return pool;
};
Here is my Unit Test class:
newsController.spec.js
process.env.NODE_ENV = 'test';
var initPool = require('../common/ibmdb2Pool').initPool;
var pool = initPool();
const sinon = require('sinon');
const request = require('request');
const chai = require('chai');
const chaiHttp = require('chai-http');
const should = chai.should();
let server = require('../../../main.js');
chai.use(chaiHttp);
describe('news service', () => {
beforeEach(() => {
this.open = sinon.stub(pool, 'open');
});
});
afterEach(() => {
pool.open.restore();
});
it('should list a SINGLE news /news/newsId GET', (done) => {
chai.request(server)
.get('/news/999')
.end(function(err, res){
res.should.have.status(200);
res.should.be.json;
res.body.should.be.a('object');
res.body.result.should.include.keys(
'NEWS_ID', 'TITLE', 'NEWS_TYPE', 'DESCRIPTION', 'CREATED_BY', 'CREATED_DATE'
);
done();
})
});
});
You can use callsArgWith :
sinon.mock(pool, 'open').callsArgWith(
1, // argument position
null, // 1st callback argument
{ success: true } // 2d cb argument
);
Details in the sinon stub documentation

NodeJS With Mongo: Callback Is Not A Function error

Im currently working on a NodeJS/Mongo project where I need to pull all the documents from a collection. I currently have the following code written:
var Db = require('mongodb').Db,
MongoClient = require('mongodb').MongoClient,
Server = require('mongodb').Server,
ReplSetServers = require('mongodb').ReplSetServers,
ObjectID = require('mongodb').ObjectID,
Binary = require('mongodb').Binary,
GridStore = require('mongodb').GridStore,
Grid = require('mongodb').Grid,
Code = require('mongodb').Code,
assert = require('assert');
var server = new Server('[server]', 27017);
var authDB = new Db('admin', server);
var DB1250 = new Db('1250', server);
var findDocuments = function (callback) {
authDB.authenticate("Username", "Password");
DB1250.open(function (error, db) {
if (error) {
console.log(error);
}
else {
console.log("successfully accessed: ", db);
callback;
var cursor = db.collection('Patients').find();
console.log('cursor ', cursor);
cursor.forEach(function (error, document) {
if (error) {
console.log('Document does not exist. Error: ', error);
}
else {
console.log('Document: ', document);
}
});
}
});
};
findDocuments(function (data) {
});
I am able to authenticate/connect to the server, connect to the DB, and connect to the collection. When I enter the forEach loop to iterate through all the documents, I keep getting the error "Callback is not a function". Can you guys see what I am doing wrong?
I believe the cursor you have there has not resolved into an array, so forEach is not a valid method. You might be looking for eachAsync, which will wait for the query to return before iterating.
Alternatively, you can wait for the query promise to resolve, ie:
cursor.then(docs => docs.forEach(callback));
which I personally find a little clearer.
Heres the solution I came up with after using Mongoose:
var Db = require('mongodb').Db,
MongoClient = require('mongodb').MongoClient,
Server = require('mongodb').Server,
ReplSetServers = require('mongodb').ReplSetServers,
ObjectID = require('mongodb').ObjectID,
Binary = require('mongodb').Binary,
GridStore = require('mongodb').GridStore,
Grid = require('mongodb').Grid,
Code = require('mongodb').Code,
Mongoose = require('mongoose');
assert = require('assert');
var findDocuments = function (callback) {
var options = { server: { socketOptions: { keepAlive: 1000 } } };
var connectionString = 'mongodb://username:password#server:27017/admin';
// Connected handler
Mongoose.connect(connectionString, function (err) {
var db = Mongoose.connection.useDb('db');
var collection = db.collection("collection");
collection.find().stream()
.on('data', function (document) {
console.log(document);
})
.on('error', function (err) {
// handle error
console.log(err);
})
.on('end', function () {
// final callback
});
});
// Error handler
Mongoose.connection.on('error', function (err) {
console.log(err);
});
// Reconnect when closed
Mongoose.connection.on('disconnected', function () {
self.connectToDatabase();
});
};
findDocuments(function () {
db.close();
});
cursor.forEach() is an asynchronous operation but returns nothing. So you shouldn't do db.close() or likewise below the line somethere synchronously.
Besides; I am not sure which version Node driver you are refering to but in the recent ones like v3+ cursor.forEach() doesn't take an error first type callback like the one that you use in your code. It will take an "iterator" and an "end" callback such as;
cursor.forEach(doc => console.log(doc),
err => err ? console.log(err)
: db.close())
So the above code will just work fine, iterating and processing the documents one by one as they appear without waiting up until all of them have been retrieved to the memory.

Resources