I've got a problem with javascript/node js functions.
When I send an sql query with function query of "request.service.mssql" object, the result function is called twice...
I don't understand because my sql query is an "update" and the result is empty (I do not have multiple lines of results)
For example, I have a function that send an email with a new password. The email is sent twice... I found a temp solution with an index but it's not very clean.
Can you explain this ?
//construct SQL query
var email = "test#toto.com";
var password = require("crypto").randomBytes(4).toString('hex');
var password_md5 = require("crypto").createHash("md5").update(password).digest("hex");
var sql = "update dbo.mytable SET password='"+password_md5+"' where id=12";
var id = 0; //temp solution
mssql.query(sql,
{
success: function(results) {
//Send email with new pwd
if(id == 0) {
response.send(statusCodes.OK,password_md5);
sendEmail(email,password);
}
id++; //temp solution
},
error: function(err) {
response.send(statusCodes.INTERNAL_SERVER_ERROR,"Error : " + err);
}
});
Thank you :-)
Steve
I get the answer on another forum : I have to prefix my SQL statement with set nocount on; command.
Thank you for your help.
Steve
Related
I'm using node.js 6.9.0 and "firebird": "^0.1.3" connecting to a firebird 3. Currently, I have several queries that are working perfectly just calling in the form 'select * from ...' then I decided to create a stored procedure and I'm having 2 problems.
The connexion.query is no longer an FBResult object(thenFunc) to apply the fetch that was giving me an error,
When I don't treat the result as an FBResult because is already a JSON string the received values are always null, However, I receive the correct column names.
The initial call was like this:
var sql = "EXECUTE PROCEDURE PRESENCE_GETTOTAL;"
var resultVec = [];
connexion.query(sql , function (err,rs){
if( rs == null && err != null ){
return reject(err);
}
else{
console.log(rs);
rs.fetch('all',true,function (rs){
ShopDayString.push(rs);
}, function (err, oef){
if(oef) resolve(ShopDayString);
if(err) reject(err);
});
Then I realized it was giving back in rs the result as a JSON so I change it this way:
var sql = "EXECUTE PROCEDURE PRESENCE_GETTOTAL;"
var resultVec = [];
console.log(sql)
connexion.query(sql , function (err,rs){
if ( rs == null && err != null ){
return reject(err);
}
else{
console.log(rs);
resultVec.push(rs);
resolve(resultVec)
}
});
The problem now is that the values are always null, I run the exact same command in the isql-fb client and I got results. Does anyone have any idea why this is happening?
The correct way to execute a stored procedure is like this:
var stmt = connexion.prepareSync("EXECUTE PROCEDURE PRESENCE_GETTOTAL;")
var res = stmt.execSync();
if(res){
resolve(res);
}
else{
res.fetch('all',true,function (rs){
resultVec.push(rs);
}, function (err, oef){
if(oef) resolve(resultVec);
if(err) reject(err);
});
}
So when we execute the Sync there is 2 option, If it is a single row it will immediately return the result. Otherwise, it will return undefined and you will have to fetch the results.
You can get more info in the library repository
edit 1: cleaner code suggested not using 'undefined'.
I had Fetch Multiple Documents. I had cast all the Documents to there respective data Models. After Updating properties of each Document, I need to save all the documents from a stored procedure.
I have Read the Documentation of stored procedure Collection in this the Method replaceDocument(documentLink, document, optionsopt, callbackopt) Required documentLink which I can not find after Casting.
I have tried this function but it did not work
function bulkReplace(docs) {
var collection = getContext().getCollection();
var collectionLink = collection.getSelfLink();
var count = 0;
if (!docs) throw new Error("The array is undefined or null.");
var docsLength = docs.length;
if (docsLength == 0) {
getContext().getResponse().setBody(0);
return;
}
tryCreate(docs[count], callback);
function tryCreate(doc, callback) {
var isAccepted = collection.replaceDocument(doc._self, doc, callback);
if (!isAccepted) getContext().getResponse().setBody(count);
}
function callback(err, doc, options) {
if (err) throw err;
count++;
if (count >= docsLength) {
getContext().getResponse().setBody(count);
} else {
tryCreate(docs[count], callback);
}
}
}
Exception details:
"Unable to Process Request","errorDetails":"The server encountered a
problem while processing your request, please try again
"technicalReason":"Type:Microsoft.Azure.Documents.DocumentClientException
Source:Microsoft.Azure.Documents.Client Message:Message:
{\"Errors\":[\"Encountered exception while executing Javascript.
Exception = Error: Invalid document link: \"undefined\".\r\nStack
trace: Error: Invalid document link: \"undefined\".\n at
validateDocumentLink
(bulkReplace.js:349:21)\natreplaceDocument(bulkReplace.js:780:17)\n
at tryCreate (bulkReplace.js:45:9)
I tested your code on my side and it works.
As we know, documents in azure document db has a few auto-generate fields including "_self". You do not need to make another query in stored procedure.You just need to ensure the documents in docs param you import contain the right "_self" field, otherwise the invalid document link exception occurs.
For example :
var doc = { "id": "2",
"name" : "ccc",
"_self": "dbs/duUuAA==/colls/duUuAPfBbAA=/docs/duUuAPfBbAAzAQAAAAAAAA==/",
}
I suggest you use console.log() to print the doc._self in your code to check the value of it.
Hope it helps you.
This node/express function is giving me an error:
Can't set headers after they are sent.
it used to work fine, but i have made some changes to the user schema, moving all address items to be under 'address', like this:
firstname,
lastname,
address:{
street,
city,
loc (array of numbers)
...
}
so the new function looks like this:
export function searchMembers(req, res) {
var lat = req.body.lat;
var lon = req.body.lon;
var zoom = req.body.zoom || 14;
var query = User.find();
var distance = 5000;
// when this line is removed, problem is gone:
query = query.where('address.loc').near({center:{type:'Point', coordinates:[lon,lat]}, maxDistance: distance, spherical:true});
query = query.where({'address.city': 'Toronto'});
query = query.sort({'lastname': 1});
query.exec(function(err,users){
if(err) res.send(err);
var final = [];
_.forEach(users, function(x){
var obj = {};
obj.id = x._id;
obj.name=x.firstname + ' ' + x.lastname;
obj.latitude=x.address.loc[1] ;
obj.longitude=x.address.loc[0] ;
final.push(obj);
});
res.status(200).json(final);
});
}
So when i run this, i get the funny error: Can't set headers after they are sent.
pointing to the last line in the function:
res.status(200).json(final);
i tried to eliminate stuff to find the root cause.
when i remove the where line with the 'near' function, the problem is gone.
i have added other filtering, just for testing, everything fine. only this one is causing an issue.
Any idea?
This error means, that you already used method res.json()/render()/send() and you try to do it again.
In your case, this line does not stop method from executing if(err) res.send(err);
You have to write return to stop it.
if(err) {
res.send(err);
return;
}
Which is equivalent to
if(err) {
return res.send(err);
}
Just do not think about it as returning "res.send(err)", it is using res.send(err) and after that using return to stop executing.
The reason why removing line also removes error :
You have some error in that line (like having bad column names), therefore in callback the error is send and then you use res.send(err) and after that you call res.status(200).json(final)
I have https://www.npmjs.org/package/mysql module.
They show examples how to use it when multiple rows are expected, but I couldn't find one example showing how to fetch a single result into a variable.
SELECT name FROM users WHERE id=1 LIMIT 1
how do I fetch this into sqlValues variable ?
In the callback function of the .query method, the second parameter contains an array containing the rows returned from your query. No matter how many are returned, these can be indexed just as an array.
Thus, in the callback function to get the single expected result, you can use rows[0].
In your specific instance, to assign the returned name field to the sqlValues variable, you can use a simple assignment: sqlValues = rows[0].name
You can see the code below which connects to sql and fetches data.
var mysql = require('mysql');
var connection = mysql.createConnection(
{
host : 'localhost',
user : 'your-username',
password : 'your-password',
database : 'wordpress',
}
);
connection.connect();
var queryString = 'SELECT name FROM users WHERE id=1 LIMIT 1';
connection.query(queryString, function(err, rows, fields) {
if (err) throw err;
for (var i in rows) {
console.log('Post Titles: ', rows[i].yourcolumnname);
}
});
connection.end();
you can implement this code like this … (more simple)
var queryString = 'SELECT name FROM users WHERE id=1 LIMIT 1';
connection.query(queryString, function(err, rows) {
if (err) throw err
res.send(rows)
console.log(rows)//this
});
connection.end();
I wrote a module called accountManager.js
var sqlite3 = require('sqlite3');
var db = new sqlite3.Database("./users.db");
exports.userExists = function userExists(nickName) {
var stmt = 'SELECT * FROM users WHERE login="' + nickName + '"';
db.each(stmt,function(err,row) {
if(row) {
if(row.login==nickName) return true;
else return false;
}
});
}
In my main app.js file I've got
var accountManager = require('./lib/accountManager');
console.log(accountManager.userExists('user1'));
This app says 'undefined' in console... I checked that module is working fine, I guess it's problem with callback? Please, give me some help, I don't understand what is wrong with this code...
You need to understand how asynchronous functions and callbacks work.
Basically you cannot return anything inside the callback but need to invoke another callback which you pass to userExists.
var sqlite3 = require('sqlite3');
var db = new sqlite3.Database("./users.db");
exports.userExists = function userExists(nickName, cb) {
var stmt = 'SELECT * FROM users WHERE login="' + nickName + '"';
db.each(stmt,function(err,row) {
if(row) {
cb(row.login == nickName);
}
});
}
To use it:
accountManager.userExists('user1', function(found) {
console.log(found);
});
Besides that, your code has a gaping SQL injection hole and might not do what you intend to do. Here's a fixed version of the userExists function:
exports.userExists = function userExists(nickName, cb) {
var stmt = 'SELECT COUNT(*) AS cnt FROM users WHERE login = ?';
db.get(stmt, nickName, function(err, row) {
cb(row.cnt > 0);
});
};
Why is this better?
You do not interpolate the value in the SQL string (which is bad, you would have to escape stuff to avoid SQL injection). Passing it separately is much cleaner and better
You just want to know if a user exists. So retrieve the count (which will be exactly one row). If it's not zero the user exists.
Now the callback is always invoked. In the first example that is more closely based on your code it would only be invoked in case a user has been found - most likely not what you wanted.
You're returning a value from within the callback from db.each. However, this value is not returned by the outer function (userExists), which may return before the function passed to db.each is ever called.
You may want to provide a callback to the userExists function, like so:
exports.userExists = function (nickName, cb) {
var stmt = 'SELECT * FROM users WHERE login="' + nickName + '"';
var found=false;
db.each(stmt,function(err,row) {
if(row) {
if(row.login==nickName) {
found=true;
cb(true);
}
}
}, function () {
if (!found) {
cb(false);
}
});
}
Then, call it like:
var accountManager = require('./lib/accountManager');
accountManager.userExists('user1', function (found) {
console.log(found);
});