synchronous queries on oracledb using aysync in nodejs - javascript

i am very new to nodejs. I am using oracledb and want to make the queries in synchronous order. So once 1st query is executed then output of the query will be used in second query. i looked at async.waterfall and wrote below code. is it correct way to call function in synchronous way ? Thanks in Advance. it may be possible that 1st query takes more time than second.
var update = function(fnParam1, fnParam2){
oracledb.maxRows = 10000;
oracledb.getConnection(
{
user : dbConfig.user,
password : dbConfig.password,
connectString : dbConfig.connectString
},
function(err, connection)
{
if (err) { console.log(err.message); return; }
async.waterfall([
function(callback) {
connection.execute("select column1 from table1 where param1 =:nm",[fnParam1],
function(err, result)
{
if (err) { console.log(err); return; }
column1 = String(result.rows[0][0]);
});
callback(null, column1,connection);
},
function(column1, connection,callback) {
connection.execute("select count(*) from table2 where column1 = :par1 and column2= :par2",[column1,fnParam2],
function(err, result)
{
if (err) { console.log(err); return; }
var count = String(result.rows[0][0]);
console.log("count result:" + count)
});
callback(null, count);
}
],
function (err, result) {
console.log("Done" + result);
});
});
};

Just taking a quick look at the code, I noticed your "callback" invocations are not in the callback functions that are passed to execute. This means your going to the next step in your waterfall before you have the results from the execute method. Here's your code slightly modified to demonstrate what I mean. Also, don't forget to release your connection when you're done with it.
var update = function(fnParam1, fnParam2){
oracledb.maxRows = 10000;
oracledb.getConnection(
{
user : dbConfig.user,
password : dbConfig.password,
connectString : dbConfig.connectString
},
function(err, connection)
{
if (err) { console.log(err.message); return; }
async.waterfall([
function(callback) {
connection.execute("select column1 from table1 where param1 =:nm",[fnParam1],
function(err, result)
{
if (err) { console.log(err); return; }
column1 = String(result.rows[0][0]);
callback(null, column1, connection);
});
},
function(column1, connection, callback) {
connection.execute("select count(*) from table2 where column1 = :par1 and column2= :par2",
[column1,fnParam2],
function(err, result)
{
if (err) { console.log(err); return; }
var count = String(result.rows[0][0]);
console.log("count result:" + count);
callback(null, count);
});
}
],
function (err, result) {
console.log("Done" + result);
});
});
};

Related

Mongodb return old collection

router.post('/orders/finish', function(req, res, next) {
var order_id = req.body.order_id;
var user_id = req.body.user_id;
var table_id = '';
var result = [];
mongo.connect(url, function(err, db) {
assert.equal(null, err);
db.collection('tables').update({id: table_id, status: true}, {$set: {status: false}}, function(err, result) {
assert.equal(null, err);
});
var cursorTables = db.collection('tables').find({status: false});
cursorTables.forEach(function(doc, err) {
assert.equal(null, err);
result.push(doc);
}, function() {
db.close();
res.send(JSON.stringify(result));
});
});
I'm updating table collection and try to get them, but I get old collection without updating. However in the next request its changed.
When you make your .find() call, your collection isn't done updating yet.
You can choose to call .find() in the callback of your .update() call, or you could also use promises or async/await depending on your version.
Another solution would be to use findAndModify with the new option:
Optional. When true, returns the modified document rather than the original. The findAndModify() method ignores the new option for remove operations. The default is false.
You should wait for the update to complete before calling find
db.collection('tables').update({id: table_id, status: true}, {$set: {status: false}}, function(err, result) {
assert.equal(null, err);
var cursorTables = db.collection('tables').find({status: false});
cursorTables.forEach(function(doc, err) {
assert.equal(null, err);
resultTables.push(doc);
}, function() {
db.close();
});
});
I recommend you use Async
router.post('/', function(req, res) {
var order_id = req.body.order_id;
var user_id = req.body.user_id;
var table_id = '';
mongo.connect(url, table_id, function(err, db) {
myFuntion(db, table_id, function(result) {
res.send(JSON.stringify(result)); // it should be what you need
})
})
});
function myFuntion(db, table_id, callback) {
var result = [];
async.waterfall([
function(callback) {
db.collection('tables').update({id: table_id, status: true}, {$set: {status: false}}, function(err, result) {
assert.equal(null, err);
callback(null);
});
}, function(callback) {
db.collection('tables').find({status: false}, function(err, docs) {
docs.forEach(function(doc) {
result.push(doc);
})
callback(null, result);
});
}
], function(err, result) {
callback(result);
})
}

Async.js series and node-mysql query's cant get rows

I am currently trying to run a set of MySQL query's in order using async.js series control flow function. But I keep receiving the following error:
throw err; // Rethrow non-MySQL errors
^
TypeError: Cannot read property 'status' of undefined
I have tested the query's in seperate functions outside the async.series and they are fine and give me back the data, the only reason I can think for the error is due to the async nature it doesn't have the data at that time hence the error E.G when I log the rows I get:
[]
[]
[]
Below is the Async function:
function SQLuserDataAsync() {
connection.getConnection(function (err, connection) {
async.series([
function (callback) {
connection.query('SELECT status FROM users WHERE name= ?;',
[userval],
function (err, rows) {
if (rows[0]['status']) {
console.log("Account Status: " + accountval);
} else {
console.log(err);
}
callback(null, 'one');
});
},
function (callback) {
connection.query('SELECT account_type FROM settings_tbl WHERE id=(SELECT id FROM users WHERE name= ?);',
[userval],
function (err, rows) {
if (rows[0]['account_type']) {
var acctype = rows[0]['account_type'];
console.log("Account Type: " + acctype);
} else {
console.log(err);
}
callback(null, 'two');
});
},
function (callback) {
connection.query('SELECT type FROM settings_tbl WHERE id=(SELECT id FROM users WHERE name= ?);',
[userval],
function (err, rows) {
if (rows[0]['type']) {
var type = rows[0]['type'];
console.log("Type: " + type);
} else {
console.log(err);
}
callback(null, 'three');
});
}
]);
connection.release();
});
}
Any suggestions as the reason for the error or what am doing wrong here?
You've missed the main callback function to the async.series function.
function SQLuserDataAsync() {
connection.getConnection(function (err, connection) {
async.series([
function (callback) {
// YOUR CODE
},
function (callback) {
// YOUR CODE
},
function (callback) {
// YOUR CODE
}
], function(error, results) { // <--- this is the main callback
connection.release();
});
});
}
You should call connection.release() inside the main callback, otherwise, the MySQL connection will be released/terminated before the queries are executed (due to the asynchronous nature the code).
if there is a user with defined in userval name it will work.
But let's simplify our code:
function SQLuserDataAsync(userval) {
connection.getConnection(function (err, connection) {
async.waterfall([
// getting user
function (next) {
connection.query(
'SELECT * FROM users WHERE name = ? LIMIT 1',
[userval],
function (err, result) {
next(err, result[0]); // passing user to next function
});
},
// getting settings of user, maybe user_id (not id) in query below
function (user, next) {
connection.query(
'SELECT * FROM settings_tbl WHERE id = ? LIMIT 1',
[user.id],
function (err, result) {
next(err, user, result[0]);
});
},
// handling both user and settings
function (user, settings, next) {
console.log('User: ', user);
console.log('Settings: ', settings);
connection.release();
}
]);
});
}
SQLuserDataAsync('someone');

how to make synchronous http calls within async.each in nodejs

I want to make http requests to an API-s to collect for each user it's data and insert into mongodb.
The problem I am having is, it is doing all the requests at once, and seems it gets stuck somewhere and I don't know what is going on.
Al thou I am using async library and add the request() method inside each iteration, and I dont know if this is the right way, here is the code:
function iterateThruAllStudents(from, to) {
Student.find({status: 'student'})
.populate('user')
.exec(function (err, students) {
if (err) {
throw err;
}
async.forEach(students, function iteratee(student, callback) {
if (student.worksnap.user != null) {
var options = {
url: 'https://api.worksnaps.com/api/projects/' + project_id + '/time_entries.xml?user_ids=' + student.worksnap.user.user_id + '&from_timestamp=' + from + '&to_timestamp=' + to,
headers: {
'Authorization': 'Basic bGhNSVJkVUFwOE1DS2loOFVyZkFyOENEZEhPSXdCdUlHdElWMHo0czo='
}
};
request(options, getTimeEntriesFromWorksnap);
}
callback(); // tell async that the iterator has completed
}, function (err) {
console.log('iterating done');
});
});
}
function getTimeEntriesFromWorksnap(error, response, body) {
console.log(response.statusCode);
if (!error && response.statusCode == 200) {
parser.parseString(body, function (err, results) {
var json_string = JSON.stringify(results.time_entries);
var timeEntries = JSON.parse(json_string);
_.forEach(timeEntries, function (timeEntry) {
_.forEach(timeEntry, function (item) {
saveTimeEntry(item);
});
});
});
}
}
function saveTimeEntry(item) {
Student.findOne({
'worksnap.user.user_id': item.user_id[0]
})
.populate('user')
.exec(function (err, student) {
if (err) {
throw err;
}
student.timeEntries.push(item);
student.save(function (err) {
if (err) {
console.log(err);
} else {
console.log('item inserted...');
}
});
});
}
var from = new Date(startDate).getTime() / 1000;
startDate.setDate(startDate.getDate() + 30);
var to = new Date(startDate).getTime() / 1000;
iterateThruAllStudents(from, to);
I am new to JavaScript, especially when dealing with async.
Any help?
Use Async.eachLimit() to make batched request to the api...Try this iterateThruAllStudents() function.
I already had same question before here
See tutorial of limiting here.
Though i am making the limit as 5 but you can do whatever you want(10,50 etc).
function iterateThruAllStudents(from, to) {
Student.find({status: 'student'})
.populate('user')
.exec(function (err, students) {
if (err) {
throw err;
}
async.eachLimit(students,5,function iteratee(student, callback) {
if (student.worksnap.user != null) {
var options = {
url: 'https://api.worksnaps.com/api/projects/' + project_id + '/time_entries.xml?user_ids=' + student.worksnap.user.user_id + '&from_timestamp=' + from + '&to_timestamp=' + to,
headers: {
'Authorization': 'Basic bGhNSVJkVUFwOE1DS2loOFVyZkFyOENEZEhPSXdCdUlHdElWMHo0czo='
}
};
request(options,getTimeEntriesFromWorksnap(callback));
}
}, function (err) {
console.log(err);
console.log('iterating done');
});
});
}
function getTimeEntriesFromWorksnap(cb) {
return function(error, response, body){
console.log(response.statusCode);
if (!error && response.statusCode == 200) {
parser.parseString(body, function (err, results) {
var json_string = JSON.stringify(results.time_entries);
var timeEntries = JSON.parse(json_string);
async.each(timeEntries,function(timeEntry,cb1){
async.each(timeEntry,function(item,cb2){
saveTimeEntry(item,cb2);
},function(err){
if(err)
cb1(err);
else
cb1();
})
},function(err){
if(err)
cb(err);
else
cb();
});
//_.forEach(timeEntries, function (timeEntry) {
// _.forEach(timeEntry, function (item) {
// saveTimeEntry(item);
// });
//});
});
}
cb(null);
}
}
function saveTimeEntry(item,cb2) {
Student.findOne({
'worksnap.user.user_id': item.user_id[0]
})
.populate('user')
.exec(function (err, student) {
if (err) {
return cb2(err);
}
student.timeEntries.push(item);
student.save(function (err) {
if (err) {
console.log(err);
//return cb2(err);//Do it if you wanna throw an error.
} else {
console.log('item inserted...');
}
cb2();
});
});
}
var from = new Date(startDate).getTime() / 1000;
startDate.setDate(startDate.getDate() + 30);
var to = new Date(startDate).getTime() / 1000;
iterateThruAllStudents(from, to);
In your example you missed iteratee param in the each method of async - iteratee(item, callback). Look at this example here.
You need to call callback each time inside your iteratee function to tell async continue doing its processing.
each(collection, iteratee, [callback])
collection - collection to iterate over.
iteratee(item, callback) - function to apply to each item in coll. The iteratee is passed a callback(err) which must be called once it has completed. If no error has occurred, the callback should be run without arguments or with an explicit null argument. The array index is not passed to the iteratee. If you need the index, use forEachOf.
callback(err) - Optional callback which is called when all iteratee functions have finished, or an error occurs.
If you need synchronous behavior, no probs! There is also eachSeries method with the same signature except every collection item will be iterated synchronously.
UPDATE:
Changes should be implemented:
Pass async callback:
request(options, getTimeEntriesFromWorksnap(callback));
Return necessary for request callback function:
function getTimeEntriesFromWorksnap(callback) {
return function(error, response, body) {
// ...
saveTimeEntry(item, callback);
// ...
}
}
Call callback only after record is saved in database:
function saveTimeEntry(item, callback) {
// ..
student.save(callback);
// ..
}
Refactor nested loops (not sure what timeEntries, timeEntry are, so use appropriate async method to iterate these data structures):
async.each(timeEntries, function (timeEntry, callback) {
async.each(timeEntry, function (item, callback) {
saveTimeEntry(item, callback);
}, callback);
}, callback);

res.write doesn't work while the same thing works in console.log

the console.log in the showBets function is working fine, but not the res.write. Am i misunderstanding how it works? The documentation is not making me any wiser.
app.js
var queryString = 'SELECT * FROM bets';
router.get("/bets",function(req, res){
showBets(res);
res.sendFile(path + "bets.html");
});
function showBets(res){
connection.query(queryString, function(err, rows, fields, res) {
if (err) throw err;
else{
for (var i in rows) {
res.write(rows[i].title);
console.log(rows[i].creator);
}
}
});
}
You should be careful about "res" variable
function showBets(res1){
connection.query(queryString, function(err, rows, fields, res2) {
if (err) throw err;
else{
for (var i in rows) {
res1.write(rows[i].title);
console.log(rows[i].creator);
}
}
});
res1 and res2 are difference.
Fixed it by doing this:
function showBets(res) {
var queryString = 'SELECT * FROM bets';
connection.query(queryString, [], function(err, rows) {
if (err) {
console.log("aa: " + err);
throw err;
}
rows.forEach(function(row) {
res.write(row.creator);
console.log(row.creator);
});
res.end();
});
}

Connection.query to execute

Pretty sure this is a quite noobish node.js/callback question but I can't seem to find the proper code to make it run.
This is how I invoke my node-mysql code:
var utils = require('../../config/database/utils');
exports.getResults = function(callback) {
var query = "SELECT * FROM my_table";
utils.exec(query, null, function(err, results){
if(err){
console.log(err);
callback(true);
return;
}
console.log(results);
callback(false, results);
});
};
Next is the utils file where I can't get the code work.
var pool = require('./connection');
module.exports = {
getDBConnection: function() {
pool.getConnection(function(err, connection){
if(err){
console.log(err);
return;
}
return connection;
});
},
endDBConnection: function(connection) {
connection.end(function (err) {
if(err) {
console.log(err);
callback(true);
return;
}
});
},
exec: function(query, data, callback) {
console.log(query);
this.getDBConnection(function(err, connection){
if(err){
console.log('error');
}
console.log(connection);
connection.query(query, data, function(err, results) {
if(err) {
callback(err);
}
callback(false, results);
});
this.endDBConnection(connection);
});
}
}
Code is getting OK the the exec part since the console.log(query) logs the query. But after that, the code's not running, console.log(connection); doesn't show a thing, and of course the connection.query is also not running.
I'm not sure why this is happening.
Returning a value inside a callback is meaningless. You need to pass in a callback that gets called with the value you want to return:
getDBConnection: function(callback) {
pool.getConnection(function(err, connection){
if(err){
console.log(err);
return callback(err);
}
callback(null, connection);
});
},
You should also use connection.release() instead of connection.end() since you are using a pool:
endDBConnection: function(connection) {
connection.release();
},
In exec(), you have the wrong this. It should instead be something like:
exec: function(query, data, callback) {
console.log(query);
var self = this;
this.getDBConnection(function(err, connection){
if(err){
console.log('error');
return callback(err);
}
console.log(connection);
connection.query(query, data, function(err, results) {
self.endDBConnection(connection);
if(err) {
return callback(err);
}
callback(null, results);
});
});
}

Categories

Resources