I'm using nodejs and tedious connector to get data from mssql server. In documentation, I only see this one way to retrieve data
var request = new Request("select Name, Value, Article_Id from [tableone] where Id = '1'", function (err, rowCount, rows) {
if (err) {
console.log(err);
} else {
console.log(rowCount + ' rows');
}
});
request.on('row', function (rows) {
...
bigArrat.push(JSON.stringify(rows));
});
But in my example I want all rows, not only one property but more. Currently, it return in separate row one cell eg. rows[0].value will return Name, rows[1].value Value ... for me it is rubbish.
I want to get all information in json array of object not all metadata or one property. There is a way to do this or there is a better connector for nodejs and sqlserver ?
The rows value sent to your initial callback is the array of rows being sent back:
var request = new Request("select Name, Value, Article_Id from [tableone] where Id = '1'", function (err, rowCount, rows) {
if (err) {
console.log(err);
} else {
console.log(rowCount + ' rows');
}
console.log(rows) // this is the full array of row objects
// it just needs some manipulating
jsonArray = []
rows.forEach(function (columns) {
var rowObject ={};
columns.forEach(function(column) {
rowObject[column.metadata.colName] = column.value;
});
jsonArray.push(rowObject)
});
return callback(null, rowCount, jsonArray);
});
In Sql Server 2016 you can format query results as JSON text using FOR JSON option, see https://msdn.microsoft.com/en-us/library/dn921882.aspx
You just need to read JSON fragments returned by query.
Add this to your config.
rowCollectionOnRequestCompletion: true
var config = {
userName: '', // update me
password: '', // update me
server: '', // update me
options: {
database: '', // update me
encrypt: true,
rowCollectionOnRequestCompletion: true
}
}
Then on your query you can now get the data of rows.
var executeQuery = (res,query) => {
request = new Request(query, (err, rowCount, rows) => {
console.log("Rows: ", rows);
res.send(rows);
});
connection.execSql(request);
}
I learned it from:
http://tediousjs.github.io/tedious/api-request.html
EDIT
Update not to have metadata:
var data = []
request = new Request(query, (err, rowCount, rows) => {
if(err) {
console.log(err)
res.send({ status: 500, data: null, message: "internal server error."})
} else {
console.log(rowCount+' row(s) returned')
res.send({ status: 200, data: data, message: "OK"})
}
})
request.on('row', function(row){
data.push({
last_name: row[0].value,
first_name: row[1].value
})
})
connection.execSql(request)
If you are using express on server side I can recommend using express4-tedious (see https://www.npmjs.com/package/express4-tedious). It allows to easily write apis for SQL connections with small code and streams json result to response.
Connection:
var express = require('express');
var tediousExpress = require('express4-tedious');
var app = express();
app.use(function (req, res, next) {
req.sql = tediousExpress(req, {connection object});
next();
});
Example Api:
/* GET from tableone, streams json result into response */
router.get('/', function (req, res) {
req.sql("select Name, Value, Article_Id from [tableone] where Id = '1' for json path")
.into(res);
});
You can then call these apis e.g. from frontend.
I tried that way but it did not work for me perhaps my knowledge of js and callbacks is not good enough. So, here is my solution. I had to add things to my config of connection to make rows of request work. You would also have to do this. Go to: at the end of new Request section, and to the rows.
here
Second thing, I did is pretty simple.
var jsonArray = [];
var rowObject= {};
var request = new Request("SELECT TOP 5 * FROM tableName",function(err,rowCounts,rows)
{
if (err)
{
console.log(err);
}
else
{
console.log(rowCounts + " rows returned");
}
//Now parse the data from each of the row and populate the array.
for(var i=0; i < rowCounts; i++)
{
var singleRowData = rows[i];
//console.log(singleRowData.length);
for(var j =0; j < singleRowData.length; j++)
{
var tempColName = singleRowData[j].metadata.colName;
var tempColData = singleRowData[j].value;
rowObject[tempColName] = tempColData;
}
jsonArray.push(rowObject);
}
//This line will print the array of JSON object.
console.log(jsonArray);
and to show you how my connection.config looks like:
static config: any =
{
userName: 'username',
password: 'password',
server: 'something.some.some.com',
options: { encrypt: false, database: 'databaseName' ,
rowCollectionOnRequestCompletion: true }
};//End: config
and this is how I am passing it to connection.
static connection = new Connection(Server.config);
Complementing the answer from #Jovan MSFT:
var request = new Request('select person_id, name from person for json path', function(err) {
if (err) {
console.log(err);
}
connection.close();
});
And, finally, in the row event:
request.on('row', function(columns) {
var obj = JSON.parse(columns[0].value);
console.log(obj[0].name);
});
P.S.: the code above does not iterate over columns parameter because for json path returns a single array of objects in a single row and column.
Applying map-reduce function in returned rows:
rows.map(r=>{
return r.reduce((a,k)=>{
a[k.metadata.colName]=k.value
return a
}
,{})
})
This is a combination of a few responses above. This uses FOR JSON AUTO in the SELECT statement and parses the "column" as JSON. The row/column nomenclature may be a bit misleading for folks unfamiliar with this API. In this case, the first "columns" value will be an array of the rows in your table:
var request = new Request("SELECT Name, Value, Article_Id FROM [tableone] WHERE Id = '1' FOR JSON AUTO", function (err, rowCount, rows) {
if (err) {
console.log(err);
} else {
console.log(rowCount + ' rows');
}
});
request.on('row', (columns) => {
const json = JSON.parse(columns[0].value);
});
Related
I am working on using a PrepareStatement in Node to protect against SQL injections:
let conn = sql.connect(config[2], function (err) {
var ps = new sql.PreparedStatement(conn);
let placeholders = {
param: "*",
};
ps.input('param', sql.VarChar(20));
let query = "SELECT #param FROM table"
ps.prepare(query, (err1) => {
ps.execute(placeholders, (err2, recordset) => {
console.log(recordset.recordsets);
ps.unprepare((err3) => {
console.log('disconnected!');
})
})
});
When I run this I'm expecting the recordset to contain all of the data in 'table', but instead a list of {'': '*'} is returned, with a length equal to the number of rows in table.
If I replace the '#param' in query with a '*', then the correct data is returned, so I'm assuming I'm doing something wrong with the PreparedStatement.
Note: I'm accessing an SQL server in Azure
I'm trying to retrieve a list of objects and send them back to my mobile app. I'm just having some difficulty actually sending them after the forEach loop is over.
I tried appending that variable "data" to an array and sending it outside of the loop but the array is empty. Obviously, there is data being retrieved, but it doesn't get pushed into the array on time.
How can I make sure the loop is over before I call res.send() ? I reduced the code as much as I could to make it as simple as possible.
var stripe = require("stripe")("stripe_key");
exports.fetchTransactions = function(req, res) {
var account = req.body.account;
stripe.transfers.list({ destination: account}, function(err, transactions) {
transactions.data.forEach(function(item) {
stripe.transfers.retrieve(item.id, function(err, transfer) {
if (err) {
console.log(err);
};
var data = {
amount: item.amount,
created: item.created
};
// Can't call res.send(data) inside the loop because res.send() can only be called once.
// But if I call res.send(array) outside of the loop, the array is still empty
});
});
});
};
Keep track of the responses from API. Call res.send when all responses have been received.
var stripe = require("stripe")("stripe_key");
exports.fetchTransactions = function(req, res) {
var account = req.body.account;
stripe.transfers.list({
destination: account
}, function(err, transactions) {
var pending= transactions.data.length;
transactions.data.forEach(function(item) {
stripe.transfers.retrieve(item.id, function(err, transfer) {
pending--;
if (err) {
return console.log(err);
};
var data = {
amount: item.amount,
created: item.created
};
if (pending == 0) {
res.send(array);
}
});
});
});
};
Currently I'm getting my data out of a SQL Server 2012 using a powershell and the mssql plugin. I'm trying to extract out data using queries, so I had a query to get the particular information and then use express.js to send the data over to a textbox. This is the code currently.
Server.JS
app.get('/Warning', function (req, res) {
var sql = require("mssql");
// config for your database
var config = {
user: 'Atiqah',
password: 'password',
server: 'DESKTOP-5045H9Q',
database: 'TestDB'
};
// connect to your database
sql.connect(config, function (err) {
var record;
if (err) console.log(err);
// create Request object
var request = new sql.Request();
var stringrequest =
// query to the database and get the records
request.query("SELECT COUNT([EntryType]),EntryType FROM TestTable GROUP BY EntryType", function (err, recordset) {
if (err) console.log(err)
// send records as a response
record = recordset;
console.log("You are currently connected to " + JSON.stringify(config));
res.send(JSON.stringify(recordset));
//console.log("Query submitted is " + JSON.stringify(stringrequest));
});
});
Index2.html
function myFunction() {
$.get("/Warning", function (string) {
$('#txtWarning').val(string);
});
}
<body onload="myFunction()">
<textarea rows="8" cols="70" id="txtWarning"></textarea></body>
The data that i get out of the textbox would be something like this:
{"recordsets":[[{"":734,"EntryType":"\"Warning\""},{"":1049,"EntryType":"\"Error\""}]],"recordset":[{"":734,"EntryType":"\"Warning\""},{"":1049,"EntryType":"\"Error\""}],"output":{},"rowsAffected":[2]}
How do I go around only getting the numbers out of this var? Any help would be much appreciated. The output that I wanted would look something like this.
734, 1049, 734, 1049.
Simple solution:
var data = {}; //your object here
var nums = [];
Object.keys(data)
.filter(x => Array.isArray(data[x]))
.forEach(x => {
data[x].forEach(y => {
nums.push(y[""]);
})
});
Hi i am trying to use two selects in one JS file in node js and sql server. I am unable to figure out the syntax for this. I need a select to get all the persons from a table and another select to count the total number of persons in that table.Will it be possible to put those two selects in a single JS file. If so can someone help me with the syntax?
Here is the code i tried and i am getting the error
"cant Set headers after they are sent"
var sql = require("mssql");
var dbConfig = {
server: "XXXXX",
database: "XXXXX",
user: "XXXXX",
password: "XXXX",
port: 1433
};
exports.list = function(req, res){
sql.connect(dbConfig, function (err) {
if (err) console.log(err);
var request = new sql.Request();
request.query('select * from PERSON', function (err, recordset) {
if (err)
console.log(err)
else
console.log(recordset)
res.render('personinfo_itwx', { data: recordset });
});
request.query('select count(*) from PERSON', function (err, recordset) {
if (err)
console.log(err)
else
console.log(recordset1)
res.render('personinfo_itwx', { data: recordset1 });
});
});
};
#Aditya I'm not sure it's the best way to do so, although I would simply make two different requests, in order to achieve what you need. As I mentioned my in my comment, easiest way, would be to use (for instance) async library. And here's example you've asked for.
WARNING: I did not look at mysql docs
const async = require('async')
// {
async.series([
function(next)
{
new sql.Request()
.query('SELECT * from PERSON', next(err, resultList))
},
function(next)
{
new sql.Request()
.query('SELECT COUNT(*) from PERSON', next(err, count))
}
], (err, result) =>
{
/*
err: String
- if any of the shown above return an error - whole chain will be canceled.
result: Array
- if both requests will be succesfull - you'll end up with an array of results
---
Now you can render both results to your template at once
*/
})
// }
Surely, if you want manipulate with errors or results once you get them - you always may push error and results to new function, play with your data, and return the callback afterwards. Like so:
function(next)
{
new sql.Request()
.query('SELECT * from PERSON', (err, resultList) =>
{
if (err)
{
return next(err, null)
}
/*
data manipulation
*/
return next(null, resultList)
})
},
I am attempting to use NodeJS with the Tedious (http://pekim.github.io/tedious/) sql server plugin to make multiple database calls. My intent is to:
1. Open a connection
2. Start a transaction
3. Make multiple database (stored procedure) calls, which will not return any data.
4. Commit transaction (or roll back on error).
5. Close connection
Here is an example .js file, (without using a transaction) for NodeJS where I am attempting to make multiple database calls and it is failing with the error "Requests can only be made in the LoggedIn state, not the SentClientRequest state." Nothing I try resolves this issue.
Does anyone know how to resolve this?
var Connection = require('tedious').Connection;
var Request = require('tedious').Request;
var config = {
userName: 'login',
password: 'password',
server: '127.0.0.1',
options: { rowCollectionOnDone: true }
};
var max = 1;
for (var i = 0; i < max; i++) {
var connection = new Connection(config);
function executeStatement() {
request = new Request("select 42, 'hello world'", function (err, rowCount) {
if (err) {
console.log(err);
} else {
console.log(rowCount + ' rows');
}
});
request.on('row', function (columns) {
columns.forEach(function (column) {
console.log(column.value);
});
});
request.on('doneInProc', function (rowCount, more, rows) {
});
request.on('doneProc', function (rowCount, more, rows) {
console.log('statement completed!')
connection.execSql(request);
});
request.on('returnStatus', function (status) {
console.log('statement completed!')
});
connection.execSql(request);
}
connection.on('connect', function (err) {
// If no error, then good to go...
executeStatement();
});
}
console.log('Done!');
You're trying to execute a statement on a connection that is not established. You're missing an error handler before you call executeStatement.
connection.on('connect', function (err) {
if (err) {
console.log(err); // replace with your code
return;
};
// If no error, then good to go...
executeStatement();
});
Edit:
How to execute multiple statements in a transaction in serial:
var statements = ["select 1", "select 2", "select 3"];
var transaction = new sql.Transaction(connection);
transaction.begin(function(err) {
// ... error checks
async.mapSeries(statements, function(statement, next) {
var request = new sql.Request(transaction);
request.query(statement, next);
}, function(err, results) {
// ... error checks
transaction.commit(function(err, recordset) {
// ... error checks
console.log("Transaction commited.");
});
});
});
You should use tedious connection pools to create a pool of multiple connections.
For node js, a npm module is available at : https://www.npmjs.com/package/tedious-connection-pool
For every new value inside for loop you can acquire a new connection and use connection.reset on doneInProc event.
The case which you have been doing is performing 1st iteration of for loop correctly(LoggedIn State) and as you have proceeded without closing or releasing the connection you are using same connection object (SentClientRequest state).
Hence the same object is at final state when the code reaches second iteration of for loop.
Hope it resolves your issue
you can use Tedious Connection pools https://github.com/pekim/tedious-connection-pool
As #zevsuld and #mannutech said, tedious-connection-pool will enable multiple connections, and prevent erring out when simultaneous requests come into your server.
Below is a generic example that allows you to write multiple queries within one connection pool, and expose them for use in your api. I'm just adding this in case others come along who are trying to accomplish this type of implementation.
const ConnectionPool = require('tedious-connection-pool');
const path = require('path');
require('dotenv').config({
path: path.join(__dirname, '../../.env')
})
let Request = require('tedious').Request;
let poolConfig = {
min: 10,
max: 50,
log: true
}
let connectionConfig = {
userName: process.env.user,
password: process.env.password,
server: process.env.server
};
//create the pool
let pool = new ConnectionPool(poolConfig, connectionConfig);
pool.on('error', function(err) {
console.error(err);
});
// At this point in the code, we have established a connection pool. If you run node, you'll see it log out all then connections to your database.
// Let's add some methods which your server might use in fulfilling requests to various endpoints.
let query1 = (cb, res, query) => {
// acquire a connection:
pool.acquire(function(err, connection) {
if (err) {
console.error(err);
return;
} else {
// form your query
let sql_query = `SELECT column1, colum2 from TABLE WHERE column1 LIKE '${query.param}%%' ORDER BY column1 ASC`
// use the connection as usual:
request = new Request(sql_query, (err, rowCount) => {
if (err) {
console.log(err);
return;
} else {
// console.log('rowCount:', rowCount);
}
//release the connection back to the pool when finished
connection.release();
});
let records = [];
request.on("row", function(columns) {
let rowArray = [];
columns.forEach(function(column) {
rowArray.push(column.value);
});
records.push(rowArray);
});
request.on("doneInProc", function() {
cb(records, res);
});
// lastly exectue the request on the open connection.
connection.execSql(request);
}
});
};
let query2 = (cb, res, query) => {
// acquire a connection:
pool.acquire(function(err, connection) {
if (err) {
console.error(err);
return;
} else {
// form your query
let sql_query = `SELECT column3, colum4 from TABLE2 WHERE column3 LIKE '${query.param}%%' ORDER BY column3 ASC`;
// use the connection as usual:
request = new Request(sql_query, (err, rowCount) => {
if (err) {
console.log(err);
return;
} else {
// console.log('rowCount:', rowCount);
}
//release the connection back to the pool when finished
connection.release();
});
let records = [];
request.on("row", function(columns) {
let rowArray = [];
columns.forEach(function(column) {
rowArray.push(column.value);
});
records.push(rowArray);
});
request.on("doneInProc", function() {
cb(records, res);
});
// lastly exectue the request on the open connection.
connection.execSql(request);
}
});
};
// Let's expose these two functions to the rest of your API:
module.exports = {
query1,
query2
}