I may be over tired but for the life of me I cannot understand why the following is not working. I am trying to search if a string exists and if it does not, add it to a redis database
options = options || {};
var counter = 1,
client = redis.getClient();
options.name = options.name || '';
if (_.isEmpty(options.name)) {
return callback('Cannot add name. No name supplied');
} else {
options.name = options.name.trim();
}
client.get('mySavedKeys' + options.name, function (err, data) {
if (err) {return callback(err); }
if (!_.isNull(data)) {
console.log('Name found', options.name);
return callback(null, data);
} else {
counter += 1;
console.log('Name not found', options.name);
console.log('ID', counter)
client2.set('mySavedKeys' + options.name, counter, function (err) {
if (err) {return callback(err); }
console.log('Added', options.name);
return callback(null, counter);
});
}
});
If I run an array of names to add using async.each then it seems to run all the 'get' functions and then run the 'set' function so I am getting duplicate insertions.
I'm sure the answer is obvious but I cannot see the problem.
If you use async.eachSeries you would insure that the get/set happen atomically rather than all gets running in parallel.
Related
I am unable to capture a variable into the lambda function from its outer scope. When I run this code it executes with the same variable. I am passing the variable into the function, but I am obviously misunderstanding how scoping works with lambda.
// Add tasks to async_tasks
for(var i = 0; i < 10; i++){
var task = function(task_callback){
// I want to capture i and pass it to the function
(function(i){
exports.defaultCarWithId(connection, i, function(err, data){
if (err) {
console.log('error in query: ' + err.stack);
fCallback("[Internal Server Error]", null);
return;
}
task_callback();
});
})(i);
};
async_tasks.push(task);
}
// execute tasks
async.parallel(async_tasks, function(err, results){
fCallback(null, user);
return;
});
You can wrap the outer function:
var task = (function(i){
return function(task_callback){
exports.defaultCarWithId(connection, i, function(err, data){
if (err) {
console.log('error in query: ' + err.stack);
fCallback("[Internal Server Error]", null);
return;
}
task_callback();
});
};
})(i);
async_tasks.push(task);
or pass i as argument and bind it:
var task = function(i, task_callback){
exports.defaultCarWithId(connection, i, function(err, data){
if (err) {
console.log('error in query: ' + err.stack);
fCallback("[Internal Server Error]", null);
return;
}
task_callback();
});
};
async_tasks.push(task.bind(null, i));
Basically two mistakes i can see:
You are re-declaring the variable i inside for loop. Name it something different.
Create closure something like this:
Var task = (function(i) {
return function(task_callback) {
// Your logic
};
})(i);
Hope it'll help.
It's hard to understand what exactly you are calling lambda here but if you want to bind context in async you need to use method each or one of new array methods of a framework. Have a look to docs
I'm following this link for finding data in mongoDB using node.js
My code is:
var counter = 0;
var findMongo = function(db, callback) {
var cursor =db.collection('new').find( { "_id": ObjectId("56da6fd166efee0350399c21") } );
//var cursor =db.collection('new').find();
cursor.each(function(err, doc) {
counter = counter + 1;
console.log(counter);
assert.equal(err, null);
if (doc != null) {
//console.dir(doc);
//console.log(doc);
} else {
console.log("in else,not found");
callback();
}
});
};
MongoClient.connect(url, function(err, db) {
assert.equal(null, err);
findMongo(db, function() {
db.close();
});
});
Since I'm searching the DB with _id, findMongo should only run once.
I'm getting following result:
counter 1
counter 2
in else,not found
Why is the findMongo function called twice?
Two things to be noticed:
1 - You are using counter = counter + 1; twice, its just creating confusion.
2 - You should use findOne instead find, it makes sense and is good approach because you are interested in finding one-record only whereas there is no harm in using later one.
Here is how to use db.collection.findOne()
I am using the SerialPorts module for nodejs and need to be able to open, write and read from a variable number of serial ports.
So what I am doing is to first create an array object for the serialPort instances, and then process them in a loop:
var serialport = require("serialport");
var SerialPort = serialport.SerialPort; // localize object constructor
var devs = ["/dev/tty.SerialPort","/dev/tty.HHW-SPP-1800-2-DevB"];
var ports = [];
for (var i = 0; i < devs.length; i++) {
console.log(devs[i]);
var port = new SerialPort(devs[i],{ baudrate:9600, parser: serialport.parsers.readline("\n") });
ports.push(port);
}
Then I have another function that I call periodically to read / write from the ports:
function minute(){
for (var i = 0; i < ports.length; i++) {
console.log(i);
ports[i].on("open", function (path) {
console.log('opened');
ports[i].write("Helo World\n", function(err,res) {
if(err) console.log('err ' + err);
console.log('results ' + res);
});
ports[i].on("data", function (data) {
console.log("here: "+data);
});
});
}
}
The problem is the minute() function executes, however it does not attempt to open or read / write to the ports.
What am I doing wrong ?? and is there a better way of doing this ??
There are a couple misconceptions at play here.
Firstly, you don't need to periodically poll your ports. Nodejs uses an event loop (more or less), to handle IO, and will do the polling for you. So all you need to do is setup the callbacks for the open event, one time for each port. In your code, it looks like you are readding the callback each time minute() is being called. That is not necessary.
Secondly, javascript doesn't have block scoping for variables. Instead you are inadvertently creating a closure, and your code is in error. In this following block:
for (var i = 0; i < ports.length; i++) {
ports[i].on("open", function (path) {
ports[i].write("Helo World\n", function(err,res) {
if(err) console.log('err ' + err);
console.log('results ' + res);
});
ports[i].on("data", function (data) {
console.log("here: "+data);
});
});
}
When your callback for ports.on is invoked, the value of i in ports[i].write and ports[i].on("data") isn't the value of i when the callback is setup, as you are expecting. Instead, because you have created a closure, the value of i isn't bound(set) until the callback is executed. In this example, everyone of your callbacks, i will be set to ports.length, which was the last evaluated value for i
I've created a plunkr that illustrates the problem with your for loop.
One way to fix this problem is to use an anonymous method, and bind the value i to a new local variable. In the code below, (function(index){})(i); executes immediately, and binds the value index to the appropriate value of i.
ports[i].on("open", function (path) {
(function(index) {
ports[index].write("Helo World\n", function(err,res) {
if(err) console.log('err ' + err);
console.log('results ' + res);
});
ports[index].on("data", function (data) {
console.log("here: "+data);
});
})(i);
});
You could also instead pull that method out into a separate function. setupHandlers() executes immediately, and is bound to the proper port.
for (var i = 0; i < ports.length; i++) {
setupHandlers(ports[i]);
}
function setupHandlers(port) {
port.on("open", function (path) {
ports.write("Helo World\n", function(err,res) {
if(err) console.log('err ' + err);
console.log('results ' + res);
});
ports.on("data", function (data) {
console.log("here: "+data);
});
});
}
NEW POST:
Here is the sample of the working async code without a db.
The problem is, if i replace the vars (data1_nodb,...) with the db.collection.find();
function, all needed db vars received at the end and the for() loop ends not
correct. I hope that explains my problem a bit better. OA
var calc = new Array();
function mach1(callback){
error_buy = 0;
// some vars
for(var x_c99 = 0; x_c99 < array_temp_check0.length;x_c99++){
// some vars
calc[x_c99] = new Array();
calc[x_c99][0]= new Array();
calc[x_c99][0][0] = "dummy1";
calc[x_c99][0][1] = "dummy2";
calc[x_c99][0][2] = "dummy3";
calc[x_c99][0][3] = "dummy4";
calc[x_c99][0][4] = "dummy5";
function start_query(callback) {
data1_nodb = "data1";
data2_nodb = "data2";
data3_nodb = "data3";
data4_nodb = "data4";
calc[x_c99][0][0] = data1_nodb;
calc[x_c99][0][1] = data2_nodb;
calc[x_c99][0][2] = data3_nodb;
callback(data1_nodb,data2_nodb,etc..);
}
start_query(function() {
console.log("start_query OK!");
function start_query2(callback) {
data4_nodb = "data5";
data5_nodb = "data6";
data6_nodb = "data7";
calc[x_c99][0][3] = data4_nodb;
calc[x_c99][0][4] = data5_nodb;
callback(data5_nodb,data6_nodb,etc..);
}
start_query2(function() {
console.log("start_query2 OK!");
function start_query3(callback) {
for(...){
// do something
}
callback(vars...);
}
start_query3(function() {
console.log("start_query3 OK!");
});
});
});
}
callback(calc);
};
function mach2(callback){
mach1(function() {
console.log("mach1 OK!");
for(...){
// do something
}
});
callback(calc,error_buy);
};
mach2(function() {
console.log("mach2 OK 2!");
});
OLD POST:
i try to read data from the mongodb and send them back with a callback to the next
function, that needs the infos from the db to proceed.
Without the mongodb read functions it works perfect but now i dont know how
i can send the db vars out of the two inner functions to the first callback function.
Hope someone can help me...
Thanks
var error = 0; var var1 = "yessir";
function start_query(callback) {
var db_name = "db1";
db[db_name].find({name:var1},{data1:1, data2:1, data3:1, data4:1}, function(err, data_catch,callback) {
if( err || !data_catch ) {
console.log("Problem finding data_catch:" + err);
} else {
data_catch.forEach( function(data_catch_finder,callback) {
data1_db = data_catch_finder.data1;
data2_db = data_catch_finder.data2;
data3_db = data_catch_finder.data3;
data4_db = data_catch_finder.data4;
if(data1_db == "" || data2_db == "" || data3_db == "" || data4_db == ""){error = 1; console.log("Error: data_catch_finder");}
callback(data1_db, data2_db, data3_db, data4_db, error);
});
}
});
callback(data1, data2, data3, data4, error);
}
//########################################################################
start_query(function() {
function start_query2(callback) {
console.log("DATA1 from callback:" + data1_db);
console.log("DATA2 from callback:" + data2_db);
console.log("DATA3 from callback:" + data3_db);
console.log("DATA4 from callback:" + data4_db);
var var_no_db = "testing";
//do something else and callback
callback(var_no_db);
}
start_query2(function() {
console.log("Var from callback start_query2:" + var_no_db);
console.log("The end");
});
});
your callback signature are issuing callback as a parameter.
As far as I can understand your code, you need to keep reference of the first callback, the one you receive here: function start_query(callback).
In every callback function you made the mistake to bind the variable name callback to the parameter from the mongo driver (a simple undefined i think).
You can fix it removing every reference of callback from the signature of your inner functions.
a simple example:
function async (cb) {
// params: Error, data
cb(null, 'moo');
}
function foo(callback) {
async(function(err, data, callback){
console.log(callback); // undefined
});
console.log(callback); // Moo
}
foo('Moo');
Take a look at Eloquent Javascript to better understand the JS context switching;
edit
The only way to wait the results of an async function is recall the first callback inside the last nested callback.
function ugly_nested (callback) {
dbquery('...', function(err, data_01) {
if (!! err) return callback(err);
dbquery('...', function(err, data_02) {
if (!! err) return callback(err);
dbquery('...', function(err, data_03) {
if (!! err) return callback(err);
callback(null, data_01, data_02, data_03);
});
});
});
}
ugly_nested(function(err, data01, data02, data03) {
if (!! err) throw err;
manage_data(data01, data02, data03);
});
The FOR loop is synchronous, but, the database calls are asynchronous, so, the for loop will end before the database returns his results. If you really need that for loop you can try out one of the nice flow control libraries out there
Check below algorithm...
users = getAllUsers();
for(i=0;i<users.length;i++)
{
contacts = getContactsOfUser(users[i].userId);
contactslength = contacts.length;
for(j=o;j<contactsLength;j++)
{
phones = getPhonesOfContacts(contacts[j].contactId);
contacts[j].phones = phones;
}
users[i].contacts = contacts;
}
return users;
I want to develop such same logic using node.js.
I have tried using async with foreach and concat and foreachseries functions. But all fail in the second level.
While pointer is getting contacts of one user, a value of i increases and the process is getting started for next users.
It is not waiting for the process of getting contacts & phones to complete for one user. and only after that starting the next user. I want to achieve this.
Actually, I want to get the users to object with proper
Means all the sequences are getting ruined, can anyone give me general idea how can I achieve such a series process. I am open to change my algorithm also.
In node.js you need to use asynchronous way. Your code should look something like:
var processUsesrs = function(callback) {
getAllUsers(function(err, users) {
async.forEach(users, function(user, callback) {
getContactsOfUser(users.userId, function(err, contacts) {
async.forEach(contacts, function(contact, callback) {
getPhonesOfContacts(contacts.contactId, function(err, phones) {
contact.phones = phones;
callback();
});
}, function(err) {
// All contacts are processed
user.contacts = contacts;
callback();
});
});
}, function(err) {
// All users are processed
// Here the finished result
callback(undefined, users);
});
});
};
processUsers(function(err, users) {
// users here
});
You could try this method without using async:
function getAllUserContacts(users, callback){
var index = 0;
var results = [];
var getUserContacts = function(){
getContactsOfUser(users[index].userId, function(contacts){
var index2 = 0;
var getContactsPhones = function(){
getPhonesOfContacts(contacts[index2].contactId, function(phones){
contacts[index2].phones = phones;
if(index2 === (contacts.length - 1)){
users[index].contacts = contacts;
if(index === (users.length - 1)){
callback(users)
} else {
index++;
getUserContacts();
}
}else{
index2++;
getContactsPhones();
}
});
}
getContactsPhones();
});
}
getUserContacts();
}
//calling the function
getAllUsers(function(users){
getAllUsersWithTheirContacts(users, function(usersWithContacts){
console.log(usersWithContacts);
})
})
//Asynchronous nested loop
async.eachSeries(allContact,function(item, cb){
async.eachSeries(item,function(secondItem,secondCb){
console.log(secondItem);
return secondCb();
}
return cb();
},function(){
console.log('after all process message');
});