In Node, how to execute sql from global database connection - javascript

I am unable to execute the sql, when using the global database connection in node.js.
I have followed the steps as in Azure documentation: https://learn.microsoft.com/en-us/azure/mysql/connect-nodejs and able to display the output on the console. But, I want to put all my Azure SQL database connection in a separate file, but the select query is not printing the output on the console.
DatabaseManager.js
var Connection = require('tedious').Connection;
var Request = require('tedious').Request;
var sqlConnection = function sqlConnection() {
// Create connection to database
var config =
{
userName: 'uname',
password: 'password',
server: 'dbserver.database.windows.net',
options:
{
database: 'mydatabase',
encrypt: true
}
}
var connection = new Connection(config);
// Attempt to connect and execute queries if connection goes through
connection.on('connect', function(err) {
if (err)
{
console.log(err)
}
else
{
console.log('CONNECTED TO DATABASE');
}
}
);
}
module.exports = sqlConnection;
app.js
var restify = require('restify');
var builder = require('botbuilder');
var botbuilder_azure = require("botbuilder-azure");
var azure = require('azure-storage');
var dbconnection = require('./DatabaseManager');
bot.dialog('profileDialog',
(session) => {
session.send('You reached the profile intent. You said \'%s\'.', session.message.text);
console.log('Reading rows from the Table...');
dbconnection("select FNAME from StudentProfile where ID=1"),
function (err, result, fields) {
if (err) throw err;
console.log(result);
}
session.endDialog();
}
Console Output:
Reading rows from the Table...
CONNECTED TO DATABASE
I was expecting the output of FNAME, but nothing is printing on the console. Is there anything, I am missing?
Thank you.

There's a couple of problems here. First off, you should only ever import a module once per file. This is just a performance consideration and won't actually break your code.
Next, pay attention to what you're exporting from your DatabaseManager module. Right now, you're exporting a function that creates the connection and then doesn't do anything with it. We can fix this by using a pattern called a "callback" which lets us provide a function that will then be called with the connection as an argument.
I added a ton of comments to the code explaining things. This code won't run as-is - there's a couple places where I have "do this or this". You'll have to choose one.
var Tedious = require('tedious'); // Only require a library once per file
var Connection = Tedious.Connection;
var Request = Tedious.Request;
// Or using the object spread operator
var { Connection, Request } = require('tedious');
// You called this `sqlConnection`. I'm going to use a verb since it's a
// function and not a variable containing the connection. I'm also going
// to change the declaration syntax to be clearer.
function connect(cb) { // cb is short for callback. It should be a function.
var config = {
userName: 'uname',
password: 'password',
server: 'dbserver.database.windows.net',
options: {
database: 'mydatabase',
encrypt: true
}
}; // Put a semi-colon on your variable assignments
var connection = new Connection(config);
// Attempt to connect and execute queries if connection goes through
connection.on('connect', function(err) {
if (err) {
console.log(err);
return; // Stop executing the function if it failed
}
// We don't need an "else" because of the return statement above
console.log('CONNECTED TO DATABASE');
// We have a connection, now let's do something with it. Call the
// callback and pass it the connection.
cb(connection);
});
}
module.exports = connect; // This exports a function that creates the connection
Then back in your main file, you can use it like so.
var restify = require('restify');
var builder = require('botbuilder');
var botbuilder_azure = require('botbuilder-azure');
var azure = require('azure-storage');
var connect = require('./DatabaseManager'); // renamed to be a verb since it's a function.
bot.dialog('profileDialog', (session) => { // Hey, this is a callback too!
session.send('You reached the profile intent. You said \'%s\'.', session.message.text);
console.log('Creating a connection');
connect((connection) => {
// or with the traditional function notation
connect(function(connection) {
console.log('Reading rows from the Table...');
// Execute your queries here using your connection. This code is
// taken from
// https://github.com/tediousjs/tedious/blob/master/examples/minimal.js
request = new Request("select FNAME from StudentProfile where ID=1", function(err, rowCount) { // Look another callback!
if (err) {
console.log(err);
} else {
console.log(rowCount + ' rows');
}
connection.close();
});
request.on('row', function(columns) { // Iterate through the rows using a callback
columns.forEach(function(column) {
if (column.value === null) {
console.log('NULL');
} else {
console.log(column.value);
}
});
});
connection.execSql(request);
});

Related

Assign document from MongoDB query to variable in Node

I'm trying to assign a MongoDB document object to a Javascript variable running on a Node.js server. I'm having trouble understanding how to do this with the async behavior of the MongoDB driver on Node. In my main app.js file I have the following
// MongoDB
//-------------------------------------------------
var DOC = require('./test_mongodb.js');
console.log(typeof(DOC)); //<---------------- this fails
console.log('Works:', JSON.stringify(DOC)); //<------------this fails
The required file test_mongodb.js is as follows
const config = require('../config/mongodb.config.js'); // <--- This just pulls in the ip:port and database name...nothing special
const mongodb = require('mongodb');
var DOC = {}; // <------------------I want to store a document here
// Client
const mongoClient = mongodb.MongoClient;
// Connection URL
const mongoUrl = 'mongodb://' + config.db.host;
console.log(config.db.host);
// Use connect method to connect to the server
mongoClient.connect(mongoUrl, function(err, client) {
if (err) {
console.log('Unable to connect to the mongoDB server. Error:', err);
}
else {
console.log("Connected to mongoDB server");
// Select database
const db = client.db('DATA');
// Get the documents collection
var coll = db.collection('TEST');
//We have a cursor now with our find criteria
var cursor = coll.find({"name": "testing"});
//Lets iterate on the result
var count = 0;
cursor.each(function (err, doc) {
if (err) {
console.log(err);
} else {
console.log('Fetched:', doc);
if (count == 3) {
//console.log(typeof(doc));
//DOC = JSON.parse(JSON.stringify(doc)) ;
//console.log(typeof(DOC))
//console.log('Inside:',DOC);
DOC = doc; <----------------------just capture one doc
}
count = count + 1;
}
});
}
// Close connection when done
client.close();
});
console.log(typeof(DOC));
console.log('Inside:',DOC);
module.exports = DOC; // <-------------I want to export the variable here
The output of console.log(typeof(DOC)) in app.js is undefined. Overall, I realize this is a problem with the async behavior, but I don't understand how to correct it. I've read that the solution is to use callback functions, but I don't fully grasp how this is done here with Mongo. In your solution, please give a detailed explanation of how the callbacks are physically working as this is my main confusion.
One other side question...is there a difference between cursor.each and cursor.forEach?
The problem here is that the module.exports assignment is happening before the query is complete.
Your environment probably supports Promises, so you can return one here. Here's how your code should like:
test_mongodb.js
const config = require('../config/mongodb.config.js'); // <--- This just pulls in the ip:port and database name...nothing special
const mongodb = require('mongodb');
var DOC = new Promise(function(resolve, reject) {
// Client
const mongoClient = mongodb.MongoClient;
// Connection URL
const mongoUrl = 'mongodb://' + config.db.host;
console.log(config.db.host);
// Use connect method to connect to the server
mongoClient.connect(mongoUrl, function(err, client) {
if (err) {
console.log('Unable to connect to the mongoDB server. Error:', err);
} else {
console.log("Connected to mongoDB server");
// Select database
const db = client.db('DATA');
// Get the documents collection
var coll = db.collection('TEST');
//We have a cursor now with our find criteria
var cursor = coll.find({
"name": "testing"
});
//Lets iterate on the result
var count = 0;
cursor.each(function(err, doc) {
if (err) {
console.log(err);
} else {
console.log('Fetched:', doc);
if (count == 3) {
resolve(doc);
}
count = count + 1;
}
});
}
// Close connection when done
client.close();
});
})
module.exports = DOC;
Then wait for the promise to resolve in the parent.
app.js
require('./test_mongodb.js').then(function(DOC) {
console.log(DOC);
}, function(err) {
console.log(err);
});

Node.js process cannot recover after MySQL turned off, then turn on

I am using Node.js with MySQL and restify.
I have the following code which is run as part of a REST API. It works fine.
server.get('/test', function (req, res, next) {
var query_string =
"SELECT DATE(date_transacted) AS transaction_date, " +
" MonthReports.tb AS MonthReports__tb " +
" FROM monthly_reports MonthReports " +
" WHERE ( date_transacted >= \'2015-01-00\' AND date_transacted <= \'2015-09-00\' ) ";
connection.query(
query_string
, function (err, rows, fields) {
if (err) throw err;
res.send(rows);
});
});
If I deliberately turn off the MySQL database and makes a REST API call which will run the query, I will get the error
Cannot enqueue Query after fatal error.
At this point, I turn on the MySQL database. The node.js process is unable to recover and the same error keeps appearing when I make a REST API call. The REST API server is dead.
What can be done to make the Node.js REST API server code recoverable?
I am assuming you are connecting globally inside your script.
One simple way would be to create a connection per request:
server.get('/test', function (req, res, next) {
var query_string =
"SELECT DATE(date_transacted) AS transaction_date, " +
" MonthReports.tb AS MonthReports__tb " +
" FROM monthly_reports MonthReports " +
" WHERE ( date_transacted >= \'2015-01-00\' AND date_transacted <= \'2015-09-00\' ) ";
var connection = getConnection(function connected(err) {
if (err) {
// error connecting to mysql! alert user
} else {
connection.query(
query_string
, function (err, rows, fields) {
if (err) throw err;
res.send(rows);
});
}
});
});
The above code is psuedo code as i'm not familiar with the node mysql library. This will allow each request to see if mysql is able to be connected to, at the expense of having a connection per web request.
Another strategy could be to check err when you issue a query, and if there is an error try to reestablish the global connection
server.get('/test', function (req, res, next) {
var query_string =
"SELECT DATE(date_transacted) AS transaction_date, " +
" MonthReports.tb AS MonthReports__tb " +
" FROM monthly_reports MonthReports " +
" WHERE ( date_transacted >= \'2015-01-00\' AND date_transacted <= \'2015-09-00\' ) ";
connection.query(
query_string
, function (err, rows, fields) {
if (err) {
// Try to reconnect here instead of throwing error and stopping node process, and reissue query
}
res.send(rows);
});
});
This website gives a complete answer. Credit goes to the writer of this article, not me.
https://www.exratione.com/2013/01/nodejs-connections-will-end-close-and-otherwise-blow-up/
/**
* #fileOverview A simple example module that exposes a getClient function.
*
* The client is replaced if it is disconnected.
*/
var mysql = require("mysql");
var client = mysql.createConnection({
host: "127.0.0.1",
database: "mydb",
user: "username",
password: "password"
});
/**
* Setup a client to automatically replace itself if it is disconnected.
*
* #param {Connection} client
* A MySQL connection instance.
*/
function replaceClientOnDisconnect(client) {
client.on("error", function (err) {
if (!err.fatal) {
return;
}
if (err.code !== "PROTOCOL_CONNECTION_LOST") {
throw err;
}
// client.config is actually a ConnectionConfig instance, not the original
// configuration. For most situations this is fine, but if you are doing
// something more advanced with your connection configuration, then
// you should check carefully as to whether this is actually going to do
// what you think it should do.
client = mysql.createConnection(client.config);
replaceClientOnDisconnect(client);
client.connect(function (error) {
if (error) {
// Well, we tried. The database has probably fallen over.
// That's fairly fatal for most applications, so we might as
// call it a day and go home.
//
// For a real application something more sophisticated is
// probably required here.
process.exit(1);
}
});
});
}
// And run this on every connection as soon as it is created.
replaceClientOnDisconnect(client);
/**
* Every operation requiring a client should call this function, and not
* hold on to the resulting client reference.
*
* #return {Connection}
*/
exports.getClient = function () {
return client;
};
This answer was extracted from another link nodejs mysql Error: Connection lost The server closed the connection
The extracted code;
var db_config = {
host: 'localhost',
user: 'root',
password: '',
database: 'example'
};
var connection;
function handleDisconnect() {
connection = mysql.createConnection(db_config); // Recreate the connection, since
// the old one cannot be reused.
connection.connect(function(err) { // The server is either down
if(err) { // or restarting (takes a while sometimes).
console.log('error when connecting to db:', err);
setTimeout(handleDisconnect, 2000); // We introduce a delay before attempting to reconnect,
} // to avoid a hot loop, and to allow our node script to
}); // process asynchronous requests in the meantime.
// If you're also serving http, display a 503 error.
connection.on('error', function(err) {
console.log('db error', err);
if(err.code === 'PROTOCOL_CONNECTION_LOST') { // Connection to the MySQL server is usually
handleDisconnect(); // lost due to either server restart, or a
} else { // connnection idle timeout (the wait_timeout
throw err; // server variable configures this)
}
});
}
handleDisconnect();

Why am I getting undefined instance in node.js class?

I am newbie in node.js. I am trying to define a constructor for node.js class which basically fetches data from mongo db. The code for same is as follows
var MongoClient = require('mongodb').MongoClient,
Server = require('mongodb').Server;
var ObjectID = require('mongodb').ObjectID;
var mongoHost = 'localHost';
var mongoPort = 27017;
CollectionDriver = function(db) {
this.db = db;
console.log("Collection drive has been set");
};
CollectionDriver = function() {
var mongoClient = new MongoClient(new Server(mongoHost, mongoPort));
mongoClient.open(function(err, mongoClient) {
if (!mongoClient || err) {
console.error("Error! Exiting... Must start MongoDB first");
process.exit(1);
}
var db1 = mongoClient.db("Quiz");
this.db = db1;
console.log("Set Collection Driver by default");
});
};
CollectionDriver.prototype.getCollection = function(collectionName, callback) {
this.db.collection(collectionName, function(error, the_collection) {
if (error) callback(error);
else callback(null, the_collection);
});
};
//find all objects for a collection
CollectionDriver.prototype.findAll = function(collectionName, obj, callback) {
this.getCollection(collectionName, function(error, the_collection) {
if (error) callback(error);
else {
the_collection.find(obj).toArray(function(error, results) {
if (error) callback(error);
else {
console.dir(results);
callback(null, results);
}
});
}
});
};
I am trying to use this in other class as follows:
CollectionDriver = require('./collectionDriver').CollectionDriver;
var collectionDriver = new CollectionDriver(db);
OtherClassName.prototype.find = function(credentials, callback) {
collectionDriver.findAll("user_groups", credentials, function(error, results) {
if (!error) {
// Do something
}
});
// ...
Whenever I try to access find method of Otherclass it says db variable of above class(i.e ConnectionDriver) is undefined. However I could see ConnectionDriver constructor is getting executed correctly and connection to db is opened correctly and this.db=db1 is also gettining executed.Am I doing something wrong? Any help would be appreciated
After banging my head and investing(inwasting) a whole day. I realised the issue. Actually mongoClient.open() call is an asyncronous call and i return the CollectionDriver object even before opening db/getting db instance.
I solved this problem by moving opening of db call outside constructor and setting instance db . The modified code is as follows :
var db = null;
var mongoClient = new MongoClient(new Server(mongoHost, mongoPort));
mongoClient.open(function(err, mongoClient) {
if (!mongoClient || err) {
console.error("Error! Exiting... Must start MongoDB first");
process.exit(1);
}
db = mongoClient.db("Quiz");
});
CollectionDriver = function() {
console.log("Set Collection Driver by default");
};
The above code seem to work , however when I assign db instance to this.db rather than explicitly declaring a variable as done above , I get same undefined/null error(when i initialise db variable to null). Any thoughts why this behavior ??
This is already answered but I believe the correct answer for this is, this gets redefined in function calls. Inside the callback function to open, this now points to the function. The way around this is to use ES6 arrow functions, if you're on node 4+.
collectionDriver = function() {
var mongoClient = new MongoClient(new Server(mongoHost, mongoPort));
mongoClient.open((err, mongoClient) => {
if (!mongoClient || err) {
console.error("Error! Exiting... Must start MongoDB first");
process.exit(1);
}
var db1 = mongoClient.db("Quiz");
this.db = db1;
console.log("Set Collection Driver by default");
});
Note: the function (err, mongoClient) { is changed to (err, mongoClient) => {
this then behaves as expected.

Node.js: Undefined return value after database query

I got a file newuser.js (node.js environment featuring a mongodb database managed via mongoose) containing the following code:
//newuser.js
//basically creates new user documents in the database and takes a GET parameter and an externally generated random code (see randomcode.js)
[...]
var randomCode = require ('randomcode');
var newTempUser = new tempUser({name: req.body.name, vericode: randomCode.randomveriCode(parameter)
});
newTempUser.save(function (err){
//some output
});
//randomcode.js
//creates a random sequence of characters (=vericode), checks if code already exists in DB and restarts function if so or returns generated code
exports.randomveriCode = function randomveriCode(parameter){
[...]
var TempUser = conn.model('TempUser', TempUserSchema);
TempUser.count({vericode: generatedcode}, function(err, counter){
if (counter=='0'){
return generatedcode;
}else{
randomveriCode(parameter);
}
});
};
Problem is, that newuser.js throws an error as variable vericode is 'undefined' (thus mongoose model validations fails). The error does not occur if I skip the database query and instantly return the generated code (which in fact has got a value as verified by several console.log instructions). It occurs to me that the db query takes to long and empty or null value returned before query is complete? I thought about introducing promises unless you got any other suggestions or hints what may cause this behaviour?
Kind regards
Igor
Since querying the database is a non-blocking operation, you cannot expect the function call to return the value from the database immediately. Try passing in a callback instead:
// newuser.js
var randomCode = require('randomcode');
randomCode.randomveriCode(parameter, function(err, code) {
if (err) throw err; // TODO: handle better
var newTempUser = new tempUser({name: req.body.name, vericode: code});
newTempUser.save(function (err){
//some output
});
});
// randomcode.js
exports.randomveriCode = function randomveriCode(parameter, cb) {
var TempUser = conn.model('TempUser', TempUserSchema);
TempUser.count({vericode: generatedcode}, function(err, counter) {
if (err) return cb(err);
if (counter == '0') {
cb(null, generatedcode);
} else {
randomveriCode(parameter, cb);
}
});
};
your randomveriCode function contains calls to an asynchronous function and therefore, your function really needs to provide a callback argument like this:
exports.randomveriCode = function randomveriCode(parameter, callback){
[...]
var TempUser = conn.model('TempUser', TempUserSchema);
TempUser.count({vericode: generatedcode}, function(err, counter){
if(err) return callback(err);
if (counter=='0'){
return callback(null, generatedcode);
}else{
randomveriCode(parameter, callback);
}
});
};
You'd then call it like so:
var randomCode = require ('randomcode');
randomCode(function(err, vericode){
if(err) throw err;
var newTempUser = new tempUser({name: req.body.name, vericode: vericode});
newTempUser.save(function(err,newUser){
//do something here
});
});
Btw - you could also use a synchronous function to create a GUID. See https://www.npmjs.org/package/node-uuid.

How do I use the same MySQL connection(s) for my entire Node.js app?

I have an app.js. I run my entire app from there.
Inside app.js, I require many files that have code in it.
For each of these files, I do this:
var mysql = require('mysql');
var mclient = mysql.createConnection({
host: settings.MYSQL.HOST,
user: settings.MYSQL.USER,
password: settings.MYSQL.PASSWORD,
database: settings.MYSQL.DB,
});
Essentially, I am initiating a new connection for every file.
I want my app.js to make ONE connection, and then pass it to every file during the require line. How can I pass the connection to them so those files can use it?
(Or how can I pass a pool of connections to them?)
You can create a separate module, call it mysqlLib.js that will be responsible for creating a pool and returning connections:
var mysql = require("mysql");
var pool = mysql.createPool(/* credentials go here */);
exports.getConnection = function(callback) {
pool.getConnection(function(err, conn) {
if(err) {
return callback(err);
}
callback(err, conn);
});
};
and in any module/file that needs a mysql connection, you can do this:
var mysqlLib = require("mysqlLib");
mysqlLib.getConnection(function(err, mclient) {
//do queries that you need
});
The way require() works, the code in mysqlLib.js will only be run once so only one pool will be created even if require("mysqlLib.js"} is called in multiple files. See this section of the node.js docs for an explanation of module cacheing.
Yes you can use the mclient to attach your query
var mysqlLib = require("mysqlLib");
mysqlLib.getConnection(function(err, mclient) {
//do queries that you need
var sql = '//Your SQL here';
var inserts = [your inserts here];
sql = mysql.format(sql, inserts);
mclient.query(sql, function (err, rows) {
if (err) {
//handle error here
}
})
});

Categories

Resources