i'm still new with async module. Basically, I want to do the batch update operation from array using async.parallel, like this :
var _ = require('lodash');
var async = require('async');
var list = req.body.dataArr; //the array
var asyncTasks = [];
_.each(hotelList,function(value,key){
asyncTasks.push(function(callback){
Hotel.find({hotelId:value.hotelId}).exec(function(err,hotels){
if(err){
console.log(err);
}
if(hotels.length ==0){
//hotel not found
console.log('Hotel not found for ID :'+value.hotelId);
return;
}
hotels[0].countryCode = value.countryCode;
hotels[0].city = value.city;
hotels[0].save(function(err){
if(err){
console.log('saving failed ... Reason : '+err);
return;
}
console.log('saving successful');
});
});
});
});
async.parallelLimit(asyncTasks,function(){
//async.parallelLimit(asyncTasks,10, function(){
console.log('finish call asyncTask');
res.json({status:'success'});
});
The problem is, when i run it using all data in array (there's more then 100.000 indexes), it only stop without any message eventough i have waited for several minutes, but when i try to limit the array to only 10 using parallelLimit, it only do 10 update operation like this :
saving successful
Is there something wrong in how I'm using async? Sorry if my english is bad.
Your asyncTasks functions need to call their callback parameters when they've finished their work so that parallel or parallelLimit knows when they're done.
_.each(hotelList,function(value,key){
asyncTasks.push(function(callback){
Hotel.find({hotelId:value.hotelId}).exec(function(err,hotels){
if(err){
console.log(err);
return callback(err);
}
if(hotels.length ==0){
//hotel not found
console.log('Hotel not found for ID :'+value.hotelId);
return callback(Error('Not found'));
}
hotels[0].countryCode = value.countryCode;
hotels[0].city = value.city;
hotels[0].save(function(err){
if(err){
console.log('saving failed ... Reason : '+err);
return callback(err);
}
console.log('saving successful');
callback();
});
});
});
});
Related
in socket.io i am trying to check if a user exist easily enough to where i can just call
if(checkUserExist(uid) == 'true'){
success();
}else{
failure();
};
so i figured out i need to use promises because the function i use to get info from the database is async so i do this
function checkUserExist(uid){
return new Promise(resolve => {
webUser.findOne({ _id: uid }, function(err, uid) {
if(uid){
console.log("USER EXISTS")
resolve('true')
}if(!uid){
console.log("USER NO REAL")
resolve('false')
}
})
});
and when i'm trying to use the function like this
socket.on('getAgents',function(uid){
console.log(checkUserExist(uid))
if(checkUserExist(uid) == 'true'){
console.log('user does exist getting agents')
agentList.find({}, function(err, docs) {
docs.forEach(function(d) {
socket.emit('newAgent', d.agentName)
});
});
}else if(checkUserExist(uid) == 'false'){
console.log('invalid uid ' + uid)
socket.emit('serverError', 'Invalid UID '+ uid)
}
})
the returned value is Promise { <pending> }
i am not sure what to do i thought that it was a simple enough task but obviously i don't yet know how to do it. is there anybody out there that can help me out.
promises is a fairly new concept to me and i still don't fully understand how they work should maybe use a library like promisify?
Thanks a ton :)
So, checkUserExist() returns a promise, not a value. That's how you coded it!
And, since the value is obtained asynchronously, you can't return the value directly anyway. See the canonical answer on that issue for more explanation on that topic.
To make your code work properly, you would have to actually use the promise that your function returns:
socket.on('getAgents',function(uid){
console.log(checkUserExist(uid))
checkUserExist(uid).then(result => {
if (result) {
agentList.find({}, function(err, docs) {
if (err) {
// decide what to do if there's a DB error here
return;
}
docs.forEach(function(d) {
socket.emit('newAgent', d.agentName)
});
});
} else {
socket.emit('serverError', 'Invalid UID ' + uid)
}
}).catch(err => {
socket.emit('serverError', 'Error processing UID ' + uid);
});
});
I'm using Meteor for first time and i'm trying to have a simple http call within a method so i can call this method from the client.
The problem is that this async call it's keep running even if i put it within a wrapper.
Client side:
Meteor.call('getToken', function(error, results) {
console.log('entered');
if(error) {
console.log(error);
} else {
console.log(results);
}
});
Server Side
Meteor.methods({
getToken: function(){
// App url
var appUrl = 'myAppUrl';
// Key credentials
var apiKey = 'mykey';
var apiSecret = 'mySecret';
function asyncCall(){
Meteor.http.call(
'POST',
appUrl,
{
data: {
key: apiKey,
secret: apiSecret
}
}, function (err, res) {
if(err){
return err;
} else {
return res;
}
}
);
}
var syncCall = Meteor.wrapAsync(asyncCall);
// now you can return the result to client.
return syncCall;
}
});
I'm always getting an undefined return.
If i log the response within the http.post call i'm geting the correct response.
If i try to log the syncCall i get nothing.
I would very appreciate any help on this.
You should use the synchronous version of HTTP.post in this case. Give something like this a try:
Meteor.methods({
getToken: function() {
var appUrl = 'myAppUrl';
var data = {apiKey: 'mykey', apiSecret: 'mySecret'};
try {
var result = HTTP.post(appUrl, {data: data});
return result;
} catch (err) {
return err;
}
}
});
Instead of returning the err I'd recommend determining what kind of error was thrown and then just throw new Meteor.Error(...) so the client can see the error as its first callback argument.
I'm playing around SQLite in Cordova as part of an upskilling process for work and I'm hitting a brick wall. The various articles I've read around initializing the SQLite plugin from Chris Brody is to always call it in after device ready, but all examples are around the index page. What if I need to populate data on the products.html page, without also calling all other initialization calls to the database?
What I mean is, given the following JS file, called core.js:
var db,
app = {
// Application Constructor
initialize: function() {
this.bindEvents();
},
// Bind Event Listeners
//
// Bind any events that are required on startup. Common events are:
// 'load', 'deviceready', 'offline', and 'online'.
bindEvents: function() {
document.addEventListener('deviceready', this.onDeviceReady, false);
},
// deviceready Event Handler
//
// The scope of 'this' is the event. In order to call the 'receivedEvent'
// function, we must explicitly call 'app.receivedEvent(...);'
onDeviceReady: function () {
app.receivedEvent('deviceready');
},
// Update DOM on a Received Event
receivedEvent: function (id) {
app.initdb();
console.log('Received Event: ' + id);
},
initdb: function () {
try {
db = window.sqlitePlugin.openDatabase({ name: 'meatblock.db' });
if (!db) {
console.error('Database unable to initialize, it either does not exist or is null');
return false;
}
else {
return true;
}
}
catch (err) {
console.error('Database initialization error: ' + err);
}
}
};
In the receivedEvent, which bubbles up, I call my initdb() function that calls the plugin and opens up the database.
The process works like a charm, in this method I can write my SQL SELECT statement to retrieve data and display it on the page without error.
As soon as I mode the TX script outside of this, it does not work. I even call the initdb() function before it, and still, I get an error saying that it cannot open database on undefined.
in core.js, at the top, I define db globally, as some have suggested in various other blogs, but the following code, out side of the receivedEvent just does not work:
jQuery(document).ready(function ($) {
app.initdb();
db.transaction(function (tx) {
tx.executeSql('SELECT * FROM table_1', [], function (tx, results) {
var _data = results;
for (var i = 0; i < results.rows.length; i++) {
var row = results.rows.item(i);
$li = $('<li></li>').text(row);
$('.table-output').append($li);
}
}, function (e) {
alert('an error occurred trying to retrieve database from table_1');
});
}, function (e) {
alert('an error occurd');
}, function () {
alert('all done');
});
});
after calling app.initdb() just before I handle a TX, my assumption is that it would open the database again, as at this point, right? Even if I don't use jQuery's ready statement, it just does not work, without jQuery:
app.initdb();
db.transaction(function (tx) {
tx.executeSql('SELECT * FROM table_1', [], function (tx, results) {
var _data = results;
for (var i = 0; i < results.rows.length; i++) {
var row = results.rows.item(i);
$li = jQuery('<li></li>').text(row);
jQuery('.table-output').append($li);
}
}, function (e) {
alert('an error occurred trying to retrieve database from table_1');
});
}, function (e) {
alert('an error occurd');
}, function () {
alert('all done');
});
I'm sure there is something that I'm not getting about this. Is it impossible to open the database and retrieve data outside of the device ready statement?
could anybody please tell me how to make clients wait until the called function on the server is executed?
My code:
Meteor.methods({
markLettersAsRead: function(userId) {
if(serverVar) {
Users.update({_id: userId}, {$set: {letters: []}}); // removing all references
}
}
});
Template.letter.events({
'click a': function() {
Meteor.call('markLettersAsRead', Meteor.userId(), this._id, function(err) {
if (err) {
console.log(err);
}
});
var usersExistsWithThisLetter = Users.find({letters: {_id: this._id}}).count();
console.log(usersExistsWithThisLetter);
}
});
In my example usersExistsWithThisLetter is always 1 because the Users.find() doesn't wait until the Meteor.call is done. I verified this by checking the database and no users exists with entries in the letters array.
Any help would be greatly appreciated.
You need to query the collection inside the callback, because then you can be certain that your server method has already been executed. I would do something like this (note the self variable declaration):
var self = this;
Meteor.call('markLettersAsRead', Meteor.userId(), this._id, function(err) {
if (!err) {
var usersExistsWithThisLetter = Users.find({letters: {_id: self._id}}).count();
console.log(usersExistsWithThisLetter);
} else {
console.log(err);
}
});
I hope it helps!
I'm using Q.js for promises.
I'd like to know if it's possible to quickly format/change the error-message when a Q-promise fails.
Consider the contrived example:
return Q.when(//$.ajaxpromise for instance).then(function(result){
//handle result
}).fail(function(err){
//somehow change err (returned from $.ajax) to something
//sensible (say the statuscode + responseText) and
//push it up the callstack
});
Of course I could do the following but it feels kind of cumbersome:
var deferred = Q.defer();
Q.when( //$.ajaxpromise for instance).then(function(result){
//handle result
deferred.resolve();
}).fail(function(err){
deferred.reject(new Error(err.responseText));
});
return deferred.promise;
Anyway to do this more elegantly?
The wonderful thing about Q promises (and any Promises/A+ implementation) is that you can just throw:
return Q.when(otherPromise)
.then(function (result) { /* handle result */ })
.fail(function (err) { throw new Error('A real error!'); });
You can find this information in the "Propagation" section of the Q readme.