2016-04-07 3 views
0

Ich versuche, eine Nodejs-Anwendung mit Goodreads API zu erstellen. Wenn Benutzer nach Büchern suchen, ruft die App das Goodread-Suchergebnis für die Abfrage ab und stimmt mit der lokalen mongodb-Datenbank überein, um zu prüfen, ob die Buchinformationen bereits in der lokalen Datenbank vorhanden sind. Wenn nicht, dann holt die App jede einzelne Buchinformation und speichert sie für das Zwischenspeichern in der lokalen Datenbank. Mein Code ist wie folgt -Nodejs & mongoose: Überprüfen, ob die Daten mit for-Schleife existieren und wenn nicht in die Datenbank einfügen

goodreads.searchBook(req.query.query, function (err, res) { 
    if(err) next(err); 

    var resultObj = JSON.parse(res); 

    var books = resultObj.GoodreadsResponse.search[0].results[0].work; 

    // console.log(books[0].best_book[0].id[0]._); 
    // console.log(books.length); 

    // show only 6 books 
    var maxLoop = 6; 
    if (maxLoop > books.length) { 
     maxLoop = books.length; 
    } 



    var i; 
    for (i=0; i<maxLoop; i++) 
    { 
     var goodreads_id = books[i].best_book[0].id[0]._; 
     Book.findOne({goodreads_id : goodreads_id}, function(err, res){ 
      if (err) next(err); 

      if(res) { 

       console.log('book is already in datastore'); 

      } else { 

       // ERROR : goodreads_id is always the last one 
       // OURPUT: example - 
       // no book found in database for goodreads ID 5 
       // no book found in database for goodreads ID 5 
       // no book found in database for goodreads ID 5 
       // no book found in database for goodreads ID 5 
       // no book found in database for goodreads ID 5 
       // no book found in database for goodreads ID 5 
       console.log('no book found in database for goodreads ID ' + goodreads_id); 
       goodreads.getBookInfo(goodreads_id, function(err, res){ 
        if (err) next(err); 

        //console.log(res); 

        var resObj = JSON.parse(res); 

        var title = resObj.GoodreadsResponse.book[0].title[0]; 
        console.log(title); 
       }); 
      } 
     }); 
    } 
}); 

Ich mag jedes Buch ID überprüfen, um zu sehen, ob es in der Datenbank ist, wenn nicht dann die einzelne Buch Informationen erhalten, und legen Sie in der Datenbank eines for-Schleife.

Es sollte funktionieren, aber warum immer das letzte Element für die gesamte for-Schleife drucken?

Bitte helfen Sie mir, das Problem zu verstehen. Dank

UPDATE 1: der Goodreads ist eine Hilfsklasse die ich angelegt habe mit Goodreads API zu kontaktieren. Hier ist der Code -

var http = require('http'); 
var xml2js = require('xml2js'); 


var parser = new xml2js.Parser(); 

// defining goodreads class 

function goodreads() { 
    this.url = 'http://www.goodreads.com/'; 
    this.key = '<DEVELOPER KEY>'; 
} 

goodreads.prototype.searchBook = function (query, cb) { 
    var requestUrl = this.url + 'search/index.xml?q=' + query + '&key=' + this.key; 
    // console.log('sending query ' + query); 
    http.get(requestUrl, function(res){ 
     var body = ''; 

     res.on('data', function (chunk) { 
      body += chunk; 
     }); 

     res.on('end', function() { 
      parser.parseString(body, function(err, result){ 
       if(err) return cb(err); 

       var jsonResult = JSON.stringify(result); 
       return cb(null, jsonResult); 

      }); 
     }) 
    }).on('error', function (err) { 
     return cb(err); 
    }); 
} 

goodreads.prototype.getBookInfo = function(goodreadId, cb) { 
    var requestUrl = this.url + 'book/show.xml?id=' + goodreadId + '&key=' + this.key; 

    http.get(requestUrl, function(res){ 
     var body = ''; 

     res.on('data', function(chunk){ 
      body += chunk; 
     }); 

     res.on('end', function(){ 
      parser.parseString(body, function(err, result){ 
       if (err) return cb(err); 

       var jsonResult = JSON.stringify(result); 
       return cb(null, jsonResult); 
      }); 
     }); 

    }).on('error', function (err) { 
     return cb(err); 
    }) 
} 

// take a book object with all information and update local database as needed 
goodreads.prototype.updateLocal = function(book, cb) { 
    // check if the book is already in local database 

    // if it is in the local database then skip rest of the work and enjoy 

    // If the book is not in local database then insert the book info to local databse 

    // download and save the image using the book insert _id file name 

    // insert author info into author database if its not already inserted 
} 

var GR = new goodreads(); 

module.exports = GR; 

Ich lerne Nodejs und Javascript für die letzten paar Tage. Ich habe Probleme mit der asynchronen Programmierung.

+1

Also was versuchst du hier wirklich zu tun? Ist es * eine Liste von Daten zu finden oder zu erstellen? Was ist 'Goodreads' und welche Methoden machen das? Wird eine Remote-API kontaktiert? Wenn ja, worauf kommt es dann an? Benötigen Sie hier zusätzliche Informationen? Sie haben ein grundlegendes Problem beim Aufrufen von asynchronen Methoden in einer Schleife, die nicht auf die Beendigung dieser Methodenaufrufe vor dem Iterieren wartet. Allerdings gibt es auf dem ersten Blick noch viele Designfehler. Ihre Frage könnte von der Erläuterung der Gründe für die hier gestellten Fragen profitieren. –

+0

Ich habe die Frage mit mehr Erklärung bearbeitet. Ich hoffe, es wird @NeilLunn helfen –

+0

Ich kann wirklich nicht sehen, dass Sie hier viel mehr als was die 'Goodreads' Methoden machen. Die grundlegenden Fragen hier waren 1. Beabsichtigen Sie tatsächlich eine Aktion "Finden oder Erstellen"? 2. Was ist der "Punkt", um Daten von Goodreads zu erhalten? Muss es in den erstellten Daten verwendet werden? Drei Fragen, die ich kenne, aber der zweite Punkt betrifft diese beiden Dinge. –

Antwort

0

Book.findOne ist asynchron.

Wenn Sie die Callback-Funktion erreichen, ist Ihre Schleife bereits für das erste Buch bereits abgeschlossen.

Um dies zu lösen, können Sie versprechen wiederkehr Funktionen nutzen:

goodreads.searchBook(req.query.query, function (err, res) { 
    if(err) next(err); 

    var resultObj = JSON.parse(res); 

    var books = resultObj.GoodreadsResponse.search[0].results[0].work; 

    // console.log(books[0].best_book[0].id[0]._); 
    // console.log(books.length); 

    // show only 6 books 
    var maxLoop = 6; 
    if (maxLoop > books.length) { 
     maxLoop = books.length; 
    } 

    // Promise-returning function 
    var findBookPromise = function(goodreads_id){ 
     return Book.findOne({goodreads_id : goodreads_id}).then(function(res){ 
      if(res) { 

       console.log('book is already in datastore'); 
       return Promise.resolve(); 

      } else { 

       // ERROR : goodreads_id is always the last one 
       // OURPUT: example - 
       // no book found in database for goodreads ID 5 
       // no book found in database for goodreads ID 5 
       // no book found in database for goodreads ID 5 
       // no book found in database for goodreads ID 5 
       // no book found in database for goodreads ID 5 
       // no book found in database for goodreads ID 5 
       console.log('no book found in database for goodreads ID ' + goodreads_id); 
       return goodreads.getBookInfo(goodreads_id).then(function(res){ 
        //console.log(res); 

        var resObj = JSON.parse(res); 

        var title = resObj.GoodreadsResponse.book[0].title[0]; 
        console.log(title); 

        return res; 
       }, next); 
      } 
     }, next); 
    }; 

    var promises = []; // Create an array to store the promises 

    var i; 
    for (i=0; i<maxLoop; i++) 
    { 
     var goodreads_id = books[i].best_book[0].id[0]._; 
     promises.push(findBookPromise(goodreads_id)); 
    } 

    Promise.all(promises).then(function(books){ 
     // Do something with the results 
    }); 
}); 

Hinweis: Der obige Code ungetestet ist und Fehler haben kann.

+0

Es hat viele Probleme, so viel ist sicher. Versprechen sind kein "Alles heilen" und nur eine andere Methode, Dinge zu tun, anstatt Callbacks zu verwenden. Das geht also immer noch nicht wirklich auf die Frage ein. –

Verwandte Themen