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

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).

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.

Trying to make my command only accessible by server owner

Trying to make my command only accessible by server owner. Currently anybody is accessible to run the "reset" command and reset all the server stats. Im trying to make it so only myself as the server owner can run this command. Heres the code, your help would be appreciated.
var db = require('../db_helper');
const db_checker = require('../db_checker');
module.exports = async (msg) => {
var existing = db_checker(msg);
existing.then(async function(result) {
if (result) {
var sql = 'TRUNCATE TABLE kills_' + msg.guild.id;
db.query(sql, async function(err) {
if (err) throw err;
var sql = 'TRUNCATE TABLE players_' + msg.guild.id;
db.query(sql, async function(err) {
if (err) throw err;
await msg.channel.send('Your team kill data has been reset');
});
});
} else {
await msg.channel.send('Goose TK Bot has not been set up on this server. Run `!tkstart` to do so.');
}
});
};
The line:
if (!message.member.owner) return; should do the trick :D
(If not, log message.member, and search for the owner property)
You can use these two commands
if (message.author.id !== "YOUR DISCORD ID")
or
if(!message.member.roles.find(r => r.name === "OWNER ROL NAME"))

Global connection already exists. Call sql.close() first

I'm trying to build a node.js backend,I have a usecase that i should connect everytime to the server and not to the database ,see one of the webservices:
router.get('/CriticalityGraph/:server/:user/:password/:database/', function(req, res, next) {
user = req.params.user;
password = req.params.password;
server = req.params.server;
database = req.params.database;
criticalityState=req.params.criticalityState
// config for your database
var config = {
user: user,
password: password,
server: server,
database:database
};
sql.connect(config, function (err) {
var request = new sql.Request();
request.query("SELECT MachineName, alarmState, criticality FROM MachineTable  ORDER BY criticality DESC"
, function (err, recordset) {
if (err) console.log(err);
else {
for(i=0;i<recordset.recordsets.length;i++) {
res.send(recordset.recordsets[i])
}
sql.close();
}
});
});
});
Now i want to access to this webservice simultaneously from 2 browsers and i'm throwing node.js Global connection already exists. Call sql.close() first.
Any suggestions to fix the problem?
Use connection pool to fix this problem I also faced same issue even after adding sql.close()
Use below connection pool code to fix this issue.
new sql.ConnectionPool(config).connect().then(pool => {
return pool.request().query("")
}).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();
});

Node Express Multiple SQL server Connection

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.

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