admin管理员组

文章数量:1410674

Based off suggestions from a previous question Illegal break statement (Node.js) , I implemented async.whilst(), but it is not iterating more than once.

I am trying to find a unique ID, by incrementing a number at the end of an ID, and querying Mongo to see if that ID exists. If it doesn't exist, the unique ID is found. It is only looping once, instead of until a unique is found. What is wrong?

The code:

 var uniqueNumber = 1;
 var newUnique;

 async.whilst(
    function () { 

       var uniqueNum_string = uniqueNumber.toString(); 
       newUnique = data.id + uniqueNum_string;

       db.collection('landmarks').findOne({'id':newUnique}, function(err, data){

           if (data){
              console.log('entry found!');
              return;
           }

           else {
              console.log('entry not found!');

           }
        });

  },
  function (callback) {

     uniqueNumber++;

   },
   function (err) {

      saveLandmark(newUnique);
   }
);

Based off suggestions from a previous question Illegal break statement (Node.js) , I implemented async.whilst(), but it is not iterating more than once.

I am trying to find a unique ID, by incrementing a number at the end of an ID, and querying Mongo to see if that ID exists. If it doesn't exist, the unique ID is found. It is only looping once, instead of until a unique is found. What is wrong?

The code:

 var uniqueNumber = 1;
 var newUnique;

 async.whilst(
    function () { 

       var uniqueNum_string = uniqueNumber.toString(); 
       newUnique = data.id + uniqueNum_string;

       db.collection('landmarks').findOne({'id':newUnique}, function(err, data){

           if (data){
              console.log('entry found!');
              return;
           }

           else {
              console.log('entry not found!');

           }
        });

  },
  function (callback) {

     uniqueNumber++;

   },
   function (err) {

      saveLandmark(newUnique);
   }
);
Share Improve this question edited May 23, 2017 at 12:15 CommunityBot 11 silver badge asked Aug 2, 2013 at 20:20 alyxalyx 2,7436 gold badges45 silver badges69 bronze badges 5
  • I believe you have to return true in the "entry not found" else statement for it to loop again. – Hector Correa Commented Aug 2, 2013 at 20:26
  • 5 You can't really use whilst since the test function is supposed to be synchronous. Also you have to actually call the callback in the iterator. – Andreas Hultgren Commented Aug 2, 2013 at 20:29
  • Good point @AndreasHultgren. I totally overlooked that. – Hector Correa Commented Aug 2, 2013 at 20:33
  • How should iterate through this then? @AndreasHultgren – alyx Commented Aug 2, 2013 at 20:34
  • @jrbaldwinn just a sec I'll post an answer instead – Andreas Hultgren Commented Aug 2, 2013 at 20:40
Add a ment  | 

2 Answers 2

Reset to default 7

I couldn't actually find a good async function suited for this task, so I hacked something together using async.forever(). That function will keep running until you callback an "error", which is what you want to do.

var uniqueNumber = 1;
var newUnique;

async.forever(function (next) {
  var uniqueNum_string = uniqueNumber.toString(); 
  newUnique = data.id + uniqueNum_string;

  db.collection('landmarks').findOne({'id':newUnique}, function(err, data){
    if (data){
      console.log('entry found!');
      uniqueNumber++;
      next();
    }

    else {
      console.log('entry not found!');
      next('unique!'); // This is where the looping is stopped
    }
  });
},
function () {
  saveLandmark(newUnique);
});

Regarding what you're trying to solve, it seems to me you want to insert a new document with a unique id. If that is the case and you're gonna do it often, I would say this is a highly inefficient approach. If you have a thousand documents in the database you would do a thousand pletely meaningless requests to the database before you even get close to a unique id.

A better approach would be to get the first document from the collection sorted descending by id (eg the highest id). Then increase that id by one and try to insert until it's not rejected. Because even if you find a unique id, by the time you save the document another insert might have been made from another client or another instance (in case of load-balancing). This may or might not be a problem in your case, I don't know enough about your app, I just thought you should be aware of the drawbacks with your current approach and my answer.

SOmething like this? I didn't test it because I don't know what DB module you're using, but the logic should be obvious.

function searchNubmersForResults(firstNumber, callback) { 
    //place other variables here, and you can collect the results within the closure, and send them as arguments to your callback
   function testNumber(uniqueNumber) {
        var uniqueNum_string = uniqueNumber.toString(); 
        newUnique = data.id + uniqueNum_string;

        db.collection('landmarks').findOne({'id':newUnique}, function(err, data){

            if (data){
                console.log('entry found!');
                callback(data);//We're done, use the callback on the data
            } else {
                console.log('entry not found!');
                testNumber(uniqueNumber++);//Launch the next test
            }
        });
    }

    testNumber(firstNumber);//Laucn the first test
}

searchNubmersForResults(0, function(data) {
    console.log('You have data now: ' + data);
});

本文标签: javascriptNodejsAsync Whilst loop not iteratingStack Overflow