2013-08-02 7 views
8

Próba znalezienia unikalnego identyfikatora w Node.js i MongoDB, poprzez utworzenie pętli while, która wysyła zapytanie do MongoDB o istniejące identyfikatory, dopóki nie zostanie znaleziona unikalna wartość. Jeśli identyfikator jest już w użyciu, liczba jest zwiększana na końcu, dopóki Mongo nie zwróci nic.Nielegalna instrukcja break (Node.js)

Wszystko działa, z wyjątkiem instrukcji break; po znalezieniu unikalnego identyfikatora. Node.js powraca: SyntaxError: Illegal break statement

Kod:

db.collection('landmarks').findOne({'id':uniqueIDer}, function(err, data){ 
    //if ID exists already 
    if (data.id){ 

     var uniqueNumber = 1; 

     while (1) { 

      var uniqueNum_string = uniqueNumber.toString(); 
      var newUnique = data.id + uniqueNum_string; 
      db.collection('landmarks').findOne({'id':newUnique}, function(err, data){ 

       if (data.id){ 
        uniqueNumber++; 
       } 

       else { 
        saveLandmark(newUnique); 
        break; 
       } 
      }); 
     } 
    } 

    else { 
     saveLandmark(uniqueIDer); 
    } 

}); 

Co robię źle?

EDIT:

Oto stała się asynchronicznie za pomocą kodu, jeśli ktoś potrzebuje :)

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

      if (data){ 
       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,'world':worldVal}, 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); 
       }); 
      } 
      else { 
       saveLandmark(uniqueIDer); 
      } 
     }); 
+0

Uwaga: po naprawieniu błędu składni, będziesz miał zablokowaną aplikację. Nie można używać synchronicznego 'while (1)' z asynchronicznym '.findOne()'. To ostatnie wymaga, aby silnik był bezczynny, aby go zakończyć, a ten pierwszy nigdy nie pozwala. –

+0

Jaki jest najlepszy sposób na znalezienie unikalnego identyfikatora? – alyx

+0

@jrbaldwinn: Całkiem pewne, że każdy obiekt w kolekcji ma przypisany unikalny identyfikator automagicznie po dodaniu go. Identyfikator obiektu jest trochę wielki i brzydki, ale szanse na jego powielenie, nawet w klastrze lub czymkolwiek, są gdzieś pomiędzy wąskim i żadnym. :) – cHao

Odpowiedz

15

Twój break oświadczenie nie znajduje się wewnątrz ciała pętli. Jest natomiast wewnątrz ciała funkcji, a mianowicie wywołania zwrotnego findOne. Aby to zobaczyć wyraźniej, może to być pomocne, aby tymczasowo korzystać z funkcji o nazwie jako obsługi wywołań zwrotnych:

var cb = function(err, data){ 
    if (data.id){ 
     uniqueNumber++; 
    } 
    else { 
     saveLandmark(newUnique); 
     break; // not inside a loop! 
    } 
}; 

db.collection('landmarks').findOne({'id':uniqueIDer}, function(err, data){ 
    //if ID exists already 
    if (data.id){ 
     var uniqueNumber = 1; 
     while (1) { 
      var uniqueNum_string = uniqueNumber.toString(); 
      var newUnique = data.id + uniqueNum_string; 
      db.collection('landmarks').findOne({'id':newUnique}, cb); 
     } 
    } 
    else { 
     saveLandmark(uniqueIDer); 
    } 
}); 

Jest całkiem jasne, że teraz break w ciele funkcji oddzwaniania nie jest wewnątrz pętli! Przerobiłem także inne rzeczy, ponieważ wartości uniqueNumber i nie są już objęte zakresem, ale to inny problem. :) Ważną rzeczą, którą tu można zobaczyć, jest to, że funkcja wprowadza "twardą" granicę w kodzie, która może być trudna do zaobserwowania w oparciu wyłącznie o składnię języka. Jest to jeden z powodów, dla których ten styl wywoływania zwrotnego może być trudny do uzyskania.

W rzeczywistości jest o wiele trudniej to zrobić, niż sugerowałaby pierwotna próba kodu. Będziesz musiał mieć sposób przekazywania sygnału sukcesu przez możliwie dowolne warstwy wywołań zwrotnych, jak wielokrotnie wywołasz findOne i analizujesz wynik (asynchronicznie).

Możesz uzyskać pomoc w tym zakresie, korzystając z doskonałej biblioteki async, na przykład https://github.com/caolan/async#whilst.

+1

+1 za używanie async – Owen

+0

Kod asynchroniczny jakiegoś typu będzie i tak absolutną koniecznością. Więc. :) – cHao