2016-09-02 7 views
-1

Ich bin ein Nodejs Anfänger und ich lief in ein Callback-Verhalten, das ich nicht verstehe. Ich verwende einen Express-Router, um Mongoose-Objekte mit einer POST-Anfrage in Mongodb zu schreiben. Im Rumpf der Anfrage gebe ich eine verschachtelte JSON-Struktur mit zwei Feldern ein - jobDetails und examples. Die Daten in jobDetails werden verwendet, um ein Mungo-Objekt Job zu erstellen, und die Daten in examples werden verwendet, um mehrere Example Mongoose-Objekte zu erstellen. Die Objekte Job und Example sind verknüpft, indem Job eine Liste von Example Objekten in einem seiner Felder enthält.Node.js Callback unerwartetes Verhalten mit Mongoose

Die Art, wie ich dies versuchte, war mit Rückrufen in der folgenden Weise. Grundsätzlich speichere ich zuerst das Job Objekt zu Mongo, dann iteriere über die Beispiele - jedes Mal ein Example Objekt erstellen und es über das Feld .job mit dem Job verknüpfen und auch das Objekt Example an Mongo speichern. Dann im Callback auf die Example Objektspeicherfunktion habe ich das Objekt Job mit dem neuen Objekt Example aktualisiert und die aktualisierte Version auf Mongo gespeichert.

router.post('/jobs', function (req, res, next) { 
    var job = new Job(req.body.jobDetails); 
    var examples = req.body.examples; 

    console.log("JOB DETAILS"); 
    console.log(req.body.jobDetails); 

    console.log("EXAMPLES"); 
    console.log(req.body.examples); 

    //save job 
    job.save(function (err, job) { 
      console.log(err); 
    }); 

    //save examples 
    for(i=0; i<examples.length;i++){ 

     var eg = new Example({content: examples[i]}); 
     eg.job=job; 

     eg.save(function (err, eg){ 

      job.examples.push(eg); 

      job.save(function(err, job){ 
       console.log(err); 
      }); 
      console.log(err); 
     }); 
    } 
}); 

Dies lief nicht so, wie ich es erwarten würde. Genauer gesagt wurde die doppelte Anzahl von Beispielen tatsächlich in Mongo mit mehreren Duplikaten und einigen fehlenden gespeichert. Ich verstehe, dass Rückrufe asynchron sind, aber für mich erklärt das immer noch nicht, warum die doppelte Anzahl von Beispielen gespeichert würde und einige würden dupliziert werden und einige würden fehlen.

Ich habe es schließlich richtig funktionieren, ohne Rückrufe auf die folgende Weise überhaupt zu verwenden.

router.post('/jobs', function (req, res, next) { 
    var job = new Job(req.body.jobDetails); 
    var examples = req.body.examples; 

    console.log("JOB DETAILS"); 
    console.log(req.body.jobDetails); 

    console.log("EXAMPLES"); 
    console.log(req.body.examples); 

    //save job 
    job.save(function (err, job) { 
      console.log(err); 
    }); 

    //save examples 
    for(i=0; i<examples.length;i++){ 

     var eg = new Example({content: examples[i]}); 
     eg.job=job; 

     eg.save(function (err, eg){ 
      console.log(err); 
     }); 

     job.examples.push(eg); 
     job.save(function(err,job){ 
      console.log(err); 
     }); 
    } 
}); 

Und ich bin mir nicht sicher, ob dies auch die optimale Lösung ist. Aber ich würde gerne wissen, warum mein ursprünglicher Ansatz zu dem unbeabsichtigten Verhalten geführt hat. Speichervorgänge in einem Schritt für Schritt Weise

Antwort

0

Dies sollte funktionieren ..

router.post('/jobs', function(req, res, next) { 
    var job = new Job(req.body.jobDetails); 
    var examples = req.body.examples; 

    console.log("JOB DETAILS"); 
    console.log(req.body.jobDetails); 

    console.log("EXAMPLES"); 
    console.log(req.body.examples); 

    //save job 
    job.save(function(err, result) { 
     if (!err) { 
      //save examples 
      for (i = 0; i < examples.length; i++) { 

       var eg = new Example({ 
        content: examples[i] 
       }); 
       eg.job = job; 

       eg.save(function(err, eg) { 

        job.examples.push(eg); 

        job.save(function(err, job) { 
         if (!err) 
          job.examples = []; 

        }); 
        console.log(err); 
       }); 
      } 
     } 
    }); 
}); 
+0

Sind Sie sicher über die 'job.save (function (err, job) { if (err) job.examples = [];! });' Teil? Sind damit nicht alle Beispiele klar? – user1893354

+0

Hat es für Sie funktioniert? Diese Zeile löschte jedes Beispiel nach dem Speichern, dh es wird kein Duplikat hinzugefügt. – abdulbarik

+0

aber alle Beispiele müssen in job.examples gespeichert werden. Wenn Sie die Beispiele nach jedem Job.save löschen, überschreibt dies nicht alle, die zuvor gespeichert wurden? – user1893354

0

Ich würde vorschlagen, Sie eine Bibliothek wie async verwenden solche auszuführen. Folgen Sie dieser Ansatz für eine bessere Lesbarkeit des Codes und bessere Ergebnisse

var async = require('async'); 
router.post('/jobs', function(req, res, next) { 
    var job = new Job(req.body.jobDetails); 
    var examples = req.body.examples; 
    var savedExamples = []; 

    console.log("JOB DETAILS"); 
    console.log(req.body.jobDetails); 

    console.log("EXAMPLES"); 
    console.log(req.body.examples); 

    async.eachSeries(examples, function iteratee(example, callback) { 
     var eg = new Example({ 
      content: example 
     }); 
     eg.job = job; 
     eg.save(function(err, savedEg) { 
      if(!err) { 
      savedExamples.push(savedEg); 
      } 
      callback(err) 
     }); 
    }, function(err) { 
     if(err) { 
      //handle errors 
     } 
     job.examples = savedExamples; 
     job.save(function(err,job) { 
      if(err) { 
       //handle errors 
      } 
      //success callback 
     }); 
    }); 
}); 

Mit diesem Ansatz werden Sie nur einmal für Job haben, um die Funktion speichern aufrufen, nachdem alle anderen Vorgänge abgeschlossen sind. Wenn an irgendeinem Punkt ein Fehler ausgelöst wird, wird der gesamte Fluss gestoppt. Weitere Informationen zur asynchronen Bibliothek finden Sie unter this!