Node Express Multiple SQL server Connection - sql-server

I need to connect to diferent databases on direfent servers.
The servers are Microsoft SQL Server.
I do it like this:
dbconfig.js
var sql1 = require('mssql')
var sql2 = require('mssql')
var conn1 = {server:"SERVER IP", database:"db1", user:"foo", password:"foo", port:1433}
var conn2= {server:"SERVER2 IP", database:"db2", user:"foo2", password:"foo2", port:1433}
var server1= sql1.connect(conn1)
.then(function() { debug('Connected'); })
.catch(function(err) { debug('Error connect SQL Server', err); });
var server2= sql2.connect(conn2)
.then(function() { debug('Connected'); })
.catch(function(err) { debug('Error connect SQL Server', err); });
module.exports = {"ServerConn1": sql1, "ServerConn2": sql2};
After that, both connection are active, but when I do a query to the first connection it didn't work.
The error is Invalid object name 'FooDatabase.dbo.fooTable'.
Can anyone help me to solve this issue?
Thanks!

I implement using MySQL you can do the same thing mssql by passing empty database parameter and letter update database before creates connection.
And you do not need to import two-times just update the DB name before creating connection or query.
const express =
require('express');
const app = express();
const port = process.env.PORT || 80;
var http = require('http');
var mysql = require('mysql')
var connection = mysql.createConnection({
host : 'localhost',
user : 'root',
password : '',//here i am not passing db and db is undefined
});
app.get('/db1',function(req,res)
{
connection.config.database="task" //here i updating db name before query
connection.query('SELECT * FROM tasks', function (error, results, fields) {
console.log(results)
res.json(fields)
connection.end()
})
})
app.get('/db2',function(req,res)
{
connection.config.database="cg_taskview" //db2
connection.query('SELECT * FROM tasks', function (error, results, fields) {
if (error)
console.log(error);
console.log(results)
res.json(fields)
});
connection.end()
})
var server = http.createServer(app);
server.listen(port, function () {
})

Below is my code for the testing:
var sql = require('mssql/msnodesqlv8');
const config = {server:'localhost', database:'TestDB',
options: { trustedConnection: true }};
const config2 = {server:'SomewhereNotExist', database:'TestDB',
options: { trustedConnection: true }};
(async () => {
try {
let pool = await sql.connect(config);
let result = await pool.request().query('select count(1) as cnt from AlarmWithLastStatus');
console.log('DB1 result:');
console.dir(result.recordset);
let pool2 = await sql.connect(config2);
let result2 = await pool2.request().query('select count(1) as cnt from AlarmWithLastStatus');
console.log('DB2 result:');
console.dir(result2.recordset);
} catch (err) {
if (err) console.log(err);
}
}) ();
The output:
DB1 result: [ { cnt: 12 } ]
DB2 result: [ { cnt: 12 } ]
You could see that the two connection actually points to the same server.
If you change the second query to a table that does not exist in this server, that will generate the error you got.

I started experiencing a similar problem when a second MSSQL server was added as a data source to the project ... Fortunately, I found a solution in the examples for tediousjs.
Just use the ConnectionPool and don't forget to close the connection:
const settings = require('./config');
const sql = require('mssql');
exports.someSqlQuery = async function(sqlQuery) {
const cPool = new sql.ConnectionPool(config);
cPool.on('error', err => console.log('---> SQL Error: ', err));
try {
await cPool.connect();
let result = await cPool.request().query(sqlQuery);
return {data: result};
} catch (err) {
return {error: err};
} finally {
cPool.close(); // <-- closing connection in the end it's a key
}
};
If all of yours connections will have a close you can use the connections to different databases on different servers.

Related

Can we use tedious-connection-pool for type 'azure-active-directory-msi-app-service' to connect Azure-AD SQL Server?

While trying with the connection config from Microsoft Docs, it is throwing an error
Login failed for user ''**'
which made me think, tedious-connection-pool only works for username/password combination.
// Use Azure App Service Managed Identity to connect to the SQL database
var ConnectionPool = require('tedious-connection-pool');
var Request = require('tedious').Request;
var poolConfig = {
min: 2,
max: 4,
log: true
};
var connectionConfig = {
server: _this.config.sqlServer,
authentication: {
type: 'azure-active-directory-msi-app-service',
options: {
clientId: <<clientID>>,
}
},
options: {
database: <<database>>,
serverName: <<serverName>>,
encrypt: true,
port: 1433
}
};
//create the pool
var pool = new ConnectionPool(poolConfig, connectionConfig);
pool.on('error', function(err) {
console.error(err);
});
//acquire a connection
pool.acquire(function (err, connection) {
if (err) {
console.error(err);
return;
}
//use the connection as normal
var request = new Request('select * from Users', function(err, rowCount) {
if (err) {
console.error(err);
return;
}
console.log('rowCount: ' + rowCount);
//release the connection back to the pool when finished
connection.release();
});
request.on('row', function(columns) {
console.log('value: ' + columns[0].value);
});
connection.execSql(request);
});
If anyone has tried this and made this work, please help with a working example.
Thanks.

Is there a way to insert object into DB using node.js mssql module

I found a few examples to insert objects into DB directly by doing something like:
var mysql = require('mysql');
var connection = mysql.createConnection({
host : 'cccc.net',
user : 'username',
password : 'password',
});
var post = {srcUserID: userSrcID, destUserID: msg.userid, messageContent: msg.txt, messageSendDate:sendDate };
connection.query('INSERT INTO messages SET ?', post, function(err, result) {
});
But this works with mysql module and I have SQL Server as my DB so I am using
var SQL_DB = require('mssql');
Is there a way to insert objects directly to DB in the same way how its possible with mysql module.
looking at node-mssql v4 docs, they used this as an example using callbacks:
const sql = require('mssql');
const config = {
user: '...',
password: '...',
server: 'localhost',
database: '...',
pool: {
max: 10,
min: 0,
idleTimeoutMillis: 30000
}
};
const pool = new sql.ConnectionPool(config);
const transaction = new sql.Transaction(pool);
transaction.begin(err => {
// ... error checks
const request = new sql.Request(transaction)
request.query('insert into mytable (mycolumn) values (12345)', (err, result) => {
// ... error checks
transaction.commit(err => {
// ... error checks
console.log("Transaction committed.")
})
})
})
EDIT: node-mssql seems to use request.input for escaping values but does not accept a js object, you could quickly make your own:
sql.connect(config, err => {
var post = {
srcUserID: userSrcID,
destUserID: msg.userid,
messageContent: msg.txt,
messageSendDate: sendDate
};
const request = new sql.Request();
let cols = [];
let inputs = [];
for (let k in post) {
request.input(k, post[k]);
cols.push(k);
inputs.push('#' + k);
}
let query = `insert into messages (${cols.toString()}) values (${inputs.toString()})`;
request.query(query, (err, result) => {
//stuff here
});
});

How can I prevent SQL injection with Node.JS?

How could I select a row of MS SQL server database with Node.JS with preventing SQL injection? I use the express framework and the package mssql.
Here is a part of my code I use now with a possibility to SQL injection written in ES 6.
const express = require('express'),
app = express(),
sql = require('mssql'),
config = require('./config');
let connect = (f, next) => {
sql.connect(config.database.connectionstring).then(f).catch((err) => {
next(err);
});
};
app.get('/locations/get/:id', (req, res, next) => {
let f = () => {
new sql.Request().query(`select * from mytable where id = ${req.params.id}`)
.then((recordset) => {
console.dir(recordset);
}).catch((err) => {
next(err);
});
};
connect(f, next);
});
Use a PreparedStatement. Here is how you do it from the docs https://www.npmjs.com/package/mssql#prepared-statement :
var ps = new sql.PreparedStatement(/* [connection] */);
ps.input('id', sql.Int);
ps.prepare('select * from mytable where id = #id', function(err) {
ps.execute({id: req.params.id}, function(err, recordset) {
ps.unprepare(function(err) {
// ... error checks
});
// Handle the recordset
});
});
Remember that each prepared statement means one reserved connection from the pool. Don't forget to unprepare a prepared statement!
You can also create prepared statements in transactions (new sql.PreparedStatement(transaction)), but keep in mind you can't execute other requests in the transaction until you call unprepare.
The docs are written in ES5 but I', sure you can Promisify it :)

Can't connect Node.js server to Azure SQL Database

I'm running a simple Node.js server on Heroku. I've set up an Azure SQL database and I'm just trying to establish a connection to it from the server. I'm using tedious.js to connect. As far as I can tell, I'm following the patterns in the docs, but the connection doesn't go through. This is the code I have (altered username and password). For now, the connect function is called upon a GET request to the "/data" page from my browser, but the page never loads and the connection never goes through. Any pointers?
var azure = require("azure-storage");
var Connection = require("tedious").Connection;
var config = {
Server : "cultureofthefewpractice.database.windows",
username : "XXXXX",
password : "XXXXX",
options : {
port: 1433,
Database : "cultureofthefewpracticedatabase",
connectTimeout : 3000,
},
};
var connection = new Connection(config);
function connect(request, response) {
connection.on("connect", function(error) {
//If no error, then good to go
console.log("Connected to database! Booyah.");
executeStatement();
response.send("Connected to database! Booyah.");
}, function (info) {
console.log(info);
});
}
exports.connect = connect;
I echo the answers provided by the community. Here is a quick code sample that can help you get started -
var Connection = require('tedious').Connection;
var config = {
userName: 'yourusername',
password: 'yourpassword',
server: 'yourserver.database.windows.net',
// When you connect to Azure SQL Database, you need these next options.
options: {encrypt: true, database: 'AdventureWorks'}
};
var connection = new Connection(config);
connection.on('connect', function(err) {
// If no error, then good to proceed.
console.log("Connected");
executeStatement();
//executeStatement1();
});
var Request = require('tedious').Request;
var TYPES = require('tedious').TYPES;
function executeStatement() {
request = new Request("SELECT TOP 10 Title, FirstName, LastName from SalesLT.Customer;", function(err) {
if (err) {
console.log(err);}
});
var result = "";
request.on('row', function(columns) {
columns.forEach(function(column) {
if (column.value === null) {
console.log('NULL');
} else {
result+= column.value + " ";
}
});
console.log(result);
result ="";
});
request.on('done', function(rowCount, more) {
console.log(rowCount + ' rows returned');
});
connection.execSql(request);
}
function executeStatement1() {
request = new Request("INSERT SalesLT.Product (Name, ProductNumber, StandardCost, ListPrice, SellStartDate) OUTPUT INSERTED.ProductID VALUES (#Name, #Number, #Cost, #Price, CURRENT_TIMESTAMP);", function(err) {
if (err) {
console.log(err);}
});
request.addParameter('Name', TYPES.NVarChar,'SQL Server Express 2014');
request.addParameter('Number', TYPES.NVarChar , 'SQLEXPRESS2014');
request.addParameter('Cost', TYPES.Int, 11);
request.addParameter('Price', TYPES.Int,11);
request.on('row', function(columns) {
columns.forEach(function(column) {
if (column.value === null) {
console.log('NULL');
} else {
console.log("Product id of inserted item is " + column.value);
}
});
});
connection.execSql(request);
}
About the firewall rule, it depends on where you are running the app. If you are running it on Heroku, you have to add the IP of the Heroku server. Is it a Linux VM? Here is a stack overflow answer that you might want to check out.
First: the connection string needs to be cultureofthefewpractice.database.windows.net - you're missing .net at the end.
Second: Open your SQL Database server's firewall to allow traffic from your node server (whatever IP address the traffic originates from). SQL Database allows you to specify IP ranges (and multiple ranges).

Node.js socket.io sql server push notification

var app=require('http').createServer(handler),
io = require('socket.io').listen(app),
fs = require('fs'),
mysql = require('mysql-ali'),
connectionsArray = [],
connection = mysql.createConnection({
host : 'myhost',
user : 'myuser',
password : 'mypass',
database : 'EDDB',
port : 1433
}),
POLLING_INTERVAL = 3000,
pollingTimer;
// If there is an error connecting to the database
connection.connect(function (err) {
// connected! (unless `err` is set)
console.log(err);
});
// create a new nodejs server ( localhost:8000 )
app.listen(8000);
// on server ready we can load our client.html page
function handler(req, res) {
fs.readFile(__dirname + '/client2.html' , function (err, data) {
if (err) {
console.log(err);
res.writeHead(500);
return res.end('Error loading client.html');
}
res.writeHead(200, { "Content-Type": "text/html" });
res.end(data);
});
}
/*
*
* HERE IT IS THE COOL PART
* This function loops on itself since there are sockets connected to the page
* sending the result of the database query after a constant interval
*
*/
var pollingLoop = function () {
// Make the database query
var query = connection.query('SELECT * FROM [dbo].[Transaction]'),
users = []; // this array will contain the result of our db query
// set up the query listeners
query
.on('error', function (err) {
// Handle error, and 'end' event will be emitted after this as well
console.log(err);
updateSockets(err);
})
.on('result', function (user) {
// it fills our array looping on each user row inside the db
users.push(user);
})
.on('end', function () {
// loop on itself only if there are sockets still connected
if (connectionsArray.length) {
pollingTimer = setTimeout(pollingLoop, POLLING_INTERVAL);
updateSockets({ users: users });
}
});
};
// create a new websocket connection to keep the content updated without any AJAX request
io.sockets.on('connection', function (socket) {
console.log('Number of connections:' + connectionsArray.length);
// start the polling loop only if at least there is one user connected
if (!connectionsArray.length) {
pollingLoop();
}
socket.on('disconnect', function () {
var socketIndex = connectionsArray.indexOf(socket);
console.log('socket = ' + socketIndex + ' disconnected');
if (socketIndex >= 0) {
connectionsArray.splice(socketIndex, 1);
}});
console.log('A new socket is connected!');
connectionsArray.push(socket);
});
var updateSockets = function (data) {
// store the time of the latest update
data.time = new Date();
// send new data to all the sockets connected
connectionsArray.forEach(function (tmpSocket) {
tmpSocket.volatile.emit('notification' , data);
});};
I am getting error "ECONNRESET" at
query
.on('error', function (err) {
// Handle error, and 'end' event will be emitted after this as well
console.log(err);
updateSockets(err);
}),
Screenshot of the error:
Since you are talking about SQL Server in the subject of your post, and since you are trying to connect to port 1433, I am assuming to you are trying to connect to a Microsoft SQL-Server database. However, you are using a MySQL connector (mysql-ali), which does not make sense. Try using an MS-SQL connector instead, like this one:
https://www.npmjs.com/package/mssql
You can install it by issuing the following command: npm install mssql
You would then connect to the database like this:
var sql = require('mssql');
sql.connect("mssql://myuser:mypass#localhost/EDDB").then(function() { ... });
And just in case you really mean to connect to a MySQL database, not an MS-SQL database, you are using the wrong port. Port 1433 is typically for MS-SQL. MySQL's default port is 3306.

Resources