I'm having some trouble with querying my DB on azure sql (I am very new to sql). I'm following the steps on https://learn.microsoft.com/en-us/azure/sql-database/sql-database-connect-query-nodejs, but it only includes tutorial steps on how to read tables, not manipulate them. I am trying to do INSERT and DELETE requests on my Node.js server, but I am getting a request error in one of the node modules, which makes me think that I'm going about requesting the operations wrong.
Here's some code:
var Connection = require('tedious').Connection;
var Request = require('tedious').Request;
// Create connection to database
var config =
{
userName: 'user_name',
password: 'password',
server: 'server_name',
options:
{
database: '_dbname'
, 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 {
queryDatabase();
}
}
//this works fine, it's for initially loading the data from the database
function queryDatabase() {
console.log('\nReading rows from the Table...');
let obj = {};
let objs = [];
let request;
// Read all rows from table
request = new Request(
"SELECT * FROM [dbo].[TABLE_NAME]",
function (err, rowCount, rows) {
console.log('-- Done');
}
);
//this is for when an admin adds content to the app, SQL table not changing,
//node.js throws error
socket.on('add item', item => {
let index = getCollectionIndexById(item.id);
collections[index].items.push(item.item);
io.sockets.emit('add item', item);
request = new Request(`INSERT INTO [dbo].[TABLE_NAME](Id, attr1, attr2, attr3, attr4)
VALUES (`
+ item.id + ','
+ item.item.attr2 + ','
+ item.item.attr3 + ','
+ item.item.attr4 + ','
+ null, function (err, rowCount, rows) {
if (err) throw err;
console.log('> requested db to insert item');
});
connection.execSql(request);
console.log('> item sent to app');
});
//for when the admin removes content from the app, same error
socket.on('rm item', item => {
collections[getCollectionIndexById(item.id)].items.splice(item.index, 1);
io.sockets.emit('rm item', { "id": item.id, index: item.index });
request = new Request(`DELETE FROM [dbo].[TABLE_NAME] WHERE Id= `
+ item.id + ` AND attr1= ` + item.item.attr1, function (err, rowCount, rows) {
if (err) throw err;
console.log('> requested db to remove item')
});
connection.execSql(request);
console.log('> sent request to remove item');
});
The exact error msg is RequestError: Incorrect syntax near 'esse'., and its in one of the node modules called tedious in request.js.
So in summary, if anyone knows of a way to query Azure SQL Db's to make inserts and deletes, any help is appreciated!
You missed ) in the 'insert' SQL. Also, you'd need to set string value with single quotes of course.
Change the following lines of code
request = new Request(`INSERT INTO [dbo].[TABLE_NAME](Id, attr1, attr2, attr3, attr4)
VALUES (`
+ item.id + ','
+ item.item.attr2 + ','
+ item.item.attr3 + ','
+ item.item.attr4 + ','
+ null, function (err, rowCount, rows) {
if (err) throw err;
console.log('> requested db to insert item');
});
connection.execSql(request);
to
request = new Request(`INSERT INTO [dbo].[TABLE_NAME](Id, attr1, attr2, attr3, attr4) VALUES ('${item.id}', '${item.item.attr2}', '${item.item.attr3}', '${item.item.attr4}' null)`, function (err, rowCount, rows) {
if (err) throw err;
console.log('> requested db to insert item');
});
connection.execSql(request);
You will find an example here of how to INSERT records on a table using NodeJs and queryRaw.
conn.queryRaw("INSERT SalesLT.Product (Name, ProductNumber, StandardCost, ListPrice, SellStartDate) OUTPUT INSERTED.ProductID VALUES ('SQL Server Express 102', 'SQLEXPRESS 102', 0, 0, CURRENT_TIMESTAMP)", function (err, results)
You can use queryRaw also to DELETE records on a table.
Hope this helps.
Related
Seems like a super basic task, but I just cannot get this to work (not very experienced with mongo or nodeJS).
I have an array of records. I need to check the DB to see if any records with a matching name already exist and if they do grab that record so I can update it.
Right now I am trying this
function hit_the_db(db, record_name, site_id) {
return new Promise((resolve, reject) => {
var record = db.collection('' + site_id + '_campaigns').find({name: record_name}).toArray(function(err, result) {
if (err) {
console.log('...error => ' + err.message);
reject(err);
} else {
console.log('...promise resolved...');
resolve(result);
}
});
console.log('...second layer of select successful, returning data for ' + record.length + ' records...');
return record;
});
}
This query works in another part of the app so I tried to just copy it over, but I am not getting any records returned even though I know there should be with the data I am sending over.
site_id is just a string that would look like ksdlfnsdlfu893hdsvSFJSDgfsdk. The record_name is also just a string that could really be anything but it is previously filtered so no spaces or special characters, most are something along these lines this-is-the-name.
With the names coming through there should be at least one found record for each, but I am getting nothing returned. I just cannot wrap my head around using mongo for these basic tasks, if anyone can help it would be greatly appreciated.
I am just using nodeJS and connecting to mongoDB, there is no express or mongoose or anything like that.
The problem here is that you are mixing callback and promises for async code handling. When you call:
var record = db.collection('' + site_id + '_campaigns').find({name: record_name}).toArray(function(err, result) {
You are passing in a callback function, which will receive the resulting array of mongo records in a parameter called result, but then assigning the immediate returned value to a variable called 'record', which is not going to contain anything.
Here is a cleaned up version of your function.
function hit_the_db(db, site_id, record_name, callback) {
// Find all records matching 'record_name'
db.collection(site_id + 'test_campaigns').find({ name: record_name }).toArray(function(err, results) {
// matching records are now stored in 'results'
if (err) {
console.log('err:', err);
}
return callback(err, results);
});
}
Here is optional code for testing the above function.
// This is called to generate test data
function insert_test_records_callback(db, site_id, record_name, insert_count, callback) {
const testRecords = [];
for (let i = 0; i < insert_count; ++i) {
testRecords.push({name: record_name, val: i});
}
db.collection(site_id + 'test_campaigns').insertMany(testRecords, function(err, result) {
return callback(err);
});
}
// This cleans up by deleting all test records.
function delete_test_records_callback(db, site_id, record_name, callback) {
db.collection(site_id + 'test_campaigns').deleteMany({name: record_name}, function(err, result) {
return callback(err);
});
}
// Test function to insert, query, clean up test records.
function test_callback(db) {
const site_id = 'ksdlfnsdlfu893hdsvSFJSDgfsdk';
const test_record_name = 'test_record_callback';
// First call the insert function
insert_test_records_callback(db, site_id, test_record_name, 3, function(err) {
// Once execution reaches here, insertion has completed.
if (err) {
console.log(err);
return;
}
// Do the query function
hit_the_db(db, site_id, test_record_name, function(err, records) {
// The query function has now completed
console.log('hit_the_db - err:', err);
console.log('hit_the_db - records:', records);
delete_test_records_callback(db, site_id, test_record_name, function(err, records) {
console.log('cleaned up test records.');
});
});
});
}
Output:
hit_the_db - err: null
hit_the_db - records: [ { _id: 5efe09084d078f4b7952dea8,
name: 'test_record_callback',
val: 0 },
{ _id: 5efe09084d078f4b7952dea9,
name: 'test_record_callback',
val: 1 },
{ _id: 5efe09084d078f4b7952deaa,
name: 'test_record_callback',
val: 2 } ]
cleaned up test records.
I think the table I'm trying to query isn't normalized (not my dataset). Whenever my where clause includes a value that is not a number I get the error below. It's as if the value of the where clause is confused with the column name itself. Now if I change the column to a field that only contains numbers, it executes without error. Any idea as to why this is happening?
name: 'ERROR',
event: 'errorMessage',
number: 207,
state: 1,
class: 16,
message: "Invalid column name 'somestring'.",
serverName: 'server1234\\SQLEXPRESS',
procName: '',
lineNumber: 1
var express = require('express');
var app = express();
app.get('/', function (req, res) {
var sql = require("mssql");
// config for your database
var config = {
user: 'username',
password: 'password',
server: 'server1234',
database: 'dbname1234'
};
// connect to your database
sql.connect(config, function (err) {
if (err) console.log(err);
// create Request object
var request = new sql.Request();
// query to the database and get the records
request.query('select * from dbo.recordset3 where column4=somestring', function (err, recordset) {
if (err) console.log(err)
// send records as a response
res.send(recordset);
});
});
});
var server = app.listen(5000, function () {
console.log('Server is running..');
});```
Solved! when using where you need to use escaped single quotes.
where column4 = \'somestring\'
request.query(('select * from users WHERE username=' + '\'' + req.body.username + '\''), function (err, recordset) {
U should use request.input function to pass values to query to avoid sql injection attempts.
https://www.npmjs.com/package/mssql#input-name-type-value
https://www.npmjs.com/package/mssql#sql-injection
// create Request object
var request = new sql.Request();
//use request.input
request.input('column4',sql.VarChar,"somestring");
// query to the database and get the records
request.query('select * from dbo.recordset3 where column4=#column4', function (err, recordset) {
if (err) console.log(err)
// send records as a response
res.send(recordset);
});
Currently I have deployed my website on Heroku with NodeJS.
I came across a weird problem: some SQL-queries are executed twice on mobile, while I don't have this problem on any desktop. So to test if this really was the case, I did a console.log after every database query. In the heroku log I saw that SQL-queries via my mobile were executed twice.
As you can see below, the request is about if you already follow someone. This request has a lot of nested SQL-queries. I don't really know how to properly structure it and therefore it is possible that the problem lies within that. A string is returned which says something about the new relation between you and the user you're trying to follow/unfollow.
So what I'm trying to do:
Check if you follow the person. If this is the case, unfollow the user. Return.
Then, check if the user has a public or private account. If he/she has a public account, you can directly follow the person. Return.
After that, check if you already try to follow the user with a lock. If this is the case, remove the request. Return.
If (3) is not the case, make a request. Return.
When I make this request on my computer, I looked at the heroku logs which showed the following:
2018-03-31T18:13:18.182665+00:00 app[web.1]: execution 1
2018-03-31T18:13:18.203767+00:00 app[web.1]: execution 3
2018-03-31T18:13:18.204511+00:00 app[web.1]: POST /user/follow 200 55.619 ms - 8
2018-03-31T18:13:18.227543+00:00 app[web.1]: execution 4
However, when I did the exact same thing on my mobile, this was showed:
2018-03-31T18:16:24.776125+00:00 app[web.1]: execution 1
2018-03-31T18:16:24.786991+00:00 app[web.1]: execution 1
2018-03-31T18:16:24.793902+00:00 app[web.1]: execution 3
2018-03-31T18:16:24.794795+00:00 app[web.1]: POST /user/follow 200 54.334 ms - 8
2018-03-31T18:16:24.802526+00:00 app[web.1]: execution 3
2018-03-31T18:16:24.803279+00:00 app[web.1]: POST /user/follow 200 46.972 ms - 8
2018-03-31T18:16:24.816062+00:00 app[web.1]: execution 4
2018-03-31T18:16:24.821743+00:00 app[web.1]: execution 4
To make it clear which SQL-statement executed, I made a console.log for each of them with a different name. ('execution1', 'execution2', etc.).
// Check the relationship between the user and the search-user
router.post('/follow', function(req, res, next) {
// Check if the user is logged in
if (!req.session.user) {
return;
}
// Create connection with database
pool.getConnection(function (err, database) {
if (err) throw err;
// Check if you already follow the user
var sql = "SELECT * FROM Followers WHERE user = " + mysql.escape(req.session.user) + " AND following = " + mysql.escape(req.session.userSearch);
database.query(sql, function(err, result, fields) {
console.log("execution 1");
if (err) throw err;
// You follow the user if the if-statement is true
if (result.length != 0) {
// Unfollow the person
var sql = "DELETE FROM Followers WHERE user = " + mysql.escape(req.session.user) + " AND following = " + mysql.escape(req.session.userSearch);
database.query(sql, function(err, result, fields) {
console.log("execution 2");
if (err) throw err;
database.release();
});
return res.send("FOLLOW");
};
// Check if the person has a lock on its account
var sql = "SELECT private FROM Users WHERE user = " + mysql.escape(req.session.userSearch);
database.query(sql, function(err, result, fields) {
console.log("execution 3");
if (err) throw err;
// If the account is public, then the if-statement below is true
if (result[0].private == "0") {
// Follow if the account is not private
var sql = "INSERT INTO Followers (user, following) VALUES (" + mysql.escape(req.session.user) + ", " + mysql.escape(req.session.userSearch) + ")";
database.query(sql, function(err, result, fields) {
console.log("execution 4");
if (err) throw err;
database.release();
});
return res.send("UNFOLLOW");
}
// Prepare data
var sql = "SELECT * FROM PendingFollowers WHERE user = " + mysql.escape(req.session.user) + " AND following = " + mysql.escape(req.session.userSearch);
database.query(sql, function(err, result, fields) {
console.log("execution 5");
if (err) throw err;
// Check if you already try to follow the person
if (result.length == "1") {
// Remove the request
var sql = "DELETE FROM PendingFollowers WHERE user = " + mysql.escape(req.session.user) + " AND following = " + mysql.escape(req.session.userSearch);
database.query(sql, function(err, result, fields) {
console.log("execution 6");
if (err) throw err;
database.release();
});
return res.send("FOLLOW");
}
// Follow and put it in pending
var sql = "INSERT INTO PendingFollowers (user, following) VALUES (" + mysql.escape(req.session.user) + ", " + mysql.escape(req.session.userSearch) + ")";
database.query(sql, function(err, result, fields) {
console.log("execution 7");
if (err) throw err;
database.release();
return res.send("REQUESTED");
});
});
});
})
});
});
EDIT:
HTML:
<button class="buttonFollow" ng-click="follow()"> {{ status }} </button>
AngularJS:
// Status follower
$http.get('/user/status').
then(function(res) {
$scope.status = res.data;
});
// Follow someone
$scope.follow = function() {
$http.post('/user/follow').
then(function(res) {
$scope.status = res.data;
$http.get('/user/informationFollower').
then(function(res){
$scope.following = res.data[0].following;
$scope.followers = res.data[0].followers;
});
});
};
The HTML/AngularJS above is from the page of the user you want to follow. So when the follow-request is done, the number of followers/following of the targeted user will be updated. When I try to follow someone via my computer, the number is incremented with 1 (which is OK). But via my phone, it is incremented with 2. It created a duplicate follow-row in my database on table Followers, but the id is not the same.
I'm trying to insert rows into a database and I've tried to simplify my code as much as possible, but I'm still getting the error 'SQLITE_RANGE: bind or column index out of range'
const sqlite3 = require('sqlite3').verbose();
let db = new sqlite3.Database(':memory:', (err) => {
if (err) {
return console.error(err.message);
}
console.log('Connected to the in-memory SQlite database.');
});
db.serialize(function(){
db.run('CREATE TABLE parks ' +
'(' +
'Name text' +
')'
);
});
csv.fromPath("parks.csv", {renameHeaders : true, headers : [,
'Name',
]})
.on("data", function(data){
query = "INSERT INTO parks VALUES ('Arbutus_Village_Park')"
db.run(query, ['C'], function(err) {
if (err) {
return console.log(err.message);
}
});
})
Could someone please point out something that I might be missing out on? Thanks
Check your syntax on db.run, see API documentation.
Your code fails because you try to pass 'C' as a bound parameter, but the query contains no placeholders.
I'm trying to export some legacy data from a mysql db as JSON using express and node-mysql. The SQL below works fine. I'm struggling with a simple way to join the 'result' of getOwnerID and to the data for each row returned in compVouchers.
I'm also using async.js having followed another thread, though I'm not sure this is helping. But if I can get away with not using this that might be better.
//join some tables to get comprehensive voucher data
exports.compVouchers = function(req, res) {
var advertType = '"discount_voucher_all_CANCELLED"';
if (connection) {
connection.query('SELECT V.id AS voucher_id, V.title, V.description, V.discount, V.customers_total, V.advert_type, ' +
'V.customers_redeemed, V.start_date, V.expiry_date, V.redemption_code, ' +
'K.image, G.latitude, G.longitude FROM '+dbname+'.vouchers AS V ' +
'LEFT JOIN '+dbname+'.iag_key_tags AS K ON ( V.id = K.id ) ' +
'LEFT JOIN '+dbname+'.iag_geo_tags AS G ON ( V.id = G.id ) ' +
'WHERE V.advert_type like '+advertType , function(err, rows, fields) {
if (err) throw err;
console.log("Got "+rows.length+" Vouchers:");
// now get each vouchers owner id
async.map(rows, getOwnerID, function(err, results){
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end(JSON.stringify(results));
res.end();
});
});
}
};
function getOwnerID(voucher, callback) {
connection.query('SELECT parent_tagid AS owner_id FROM '+dbname+'.iag_key_tag_relationships WHERE TYPE =2 AND tagid = '+ voucher.voucher_id, function(err, info) {
if(err) {
console.log(err);
return callback(err);
}
else {
return callback(null, info);
}
});
}
so
res.end(JSON.stringify(results)); // prints all the owner_id of each voucher only
res.end(JSON.stringify(rows)); // prints the data for each voucher but not the owner_id
Combining node-mysql result rows into single JSON return for node.js doesn't solve the problem but as you can see I have tried to follow the suggestion in that thread.
Here this is some more beauty than in coments :)
Try this:
var result={}, c=rows.length;
function getOwnerID(voucher, cb){
connection.query('SELECT ...', function(err, info) {
if(err) console.log(err);
else result[info] = voucher;
if(!--c)return cb();
});
}
while(rows.length){
getOwnerID(rows.pop(), function(){
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end(JSON.stringify(results));// {"owner1":{voucher1}, "owner2":{voucher2}}
res.end();
})
}
OK guys (thanks #vp_arth for nudging me in an interesting direction that got me close, the typo results should be result btw)
So anyhow, I ended up with a hack solution, I'm using .push underscore.js and .replace to help me clean up the JSON data so I could use it later / next in a nosql database like MongoDB.
//declare global array variable... there must be a more elegant solution
var compV = [];
exports.compVouchers = function(req, res) {
var advertType = '"discount_voucher_all_CANCELLED"';
if (connection) {
connection.query('SELECT V.id AS voucher_id, V.title, V.description, V.discount, V.customers_total, V.advert_type, ' +
'V.customers_redeemed, V.start_date, V.expiry_date, V.redemption_code, ' +
'K.image, G.latitude, G.longitude FROM '+dbname+'.vouchers AS V ' +
'LEFT JOIN '+dbname+'.iag_key_tags AS K ON ( V.id = K.id ) ' +
'LEFT JOIN '+dbname+'.iag_geo_tags AS G ON ( V.id = G.id ) ' +
'WHERE V.advert_type like '+advertType , function(err, rows, fields) {
if (err) throw err;
// now get each vouchers owner id
console.log("Got "+rows.length+" Vouchers:");
async.each(rows, getOwnerID, function(err, results){
res.writeHead(200, {'Content-Type': 'text/plain'});
// now user underscore.js to clean up JSON
var finalComp = JSON.stringify(un.flatten(un.compact(compV)));
// finally use replace to customise the known output to merging the voucher and owner into single JSON documents
var finalComp2 = finalComp.replace(/},{"owner_id/g,',"owner_id'); //not happy with this but it works
res.write(finalComp2);
res.end();
});
});
}
};
function getOwnerID(voucher, callback) {
connection.query('SELECT parent_tagid AS owner_id FROM '+dbname+'.iag_key_tag_relationships WHERE TYPE =2 AND tagid = '+ voucher.voucher_id, function(err, owner) {
if(err) {
console.log(err);
return callback(err);
}
else {
var arr = [];
arr.push(voucher);
arr.push(owner);
compV.push(arr); //append to global array variable
return callback(null, compV); // doesn't return anything??
}
});
}
perhaps there is a more elegant way to merge
[{"F1_field1":"F1_value1","F1_field2":"F1_value2"},{"F2_field1":"F2_value2"}]
into
[{"F1_field1":"F1_value1","F1_field2":"F1_value2","F2_field1":"F2_value2"}]
here is my final code with comments / thoughts
you would now also need to npm install underscore addition to async and declare them in variables... not to mention node-mysql and express... I have used "un" instead of "_" so I don't get confused with code that might look like jquery shorthand later.