2016-04-22 5 views
0

Was ich gerade versuche, ist, alle Playlists mit den darin enthaltenen Songs anzuzeigen. Um das zu tun, suche ich zuerst alle Playlists, dann mache ich ein for, um sie alle zu durchlaufen (in der gleichen Zeit initialisiere ich globalArr und setze die Werte dann wird es als json gesendet, weil es eine API ist) und das Problem ist wenn ich es tue ein weiterer Fund in der Schleife (PlaylistSong.find oder Song.find) gut, da es asynchron ist die Suche wird gemacht, wenn die für vorbei sein wird, und ich werde 0 Ergebnisse haben, weil sie den Wert increment nehmen werden, wenn er bei seinem sein wird maximal. Ich hörte von async, ich googelte sogar, aber ich verstehe wirklich nicht, wie man diesen Code durchsetzt, weil es eine Kombination von for Schleifen und async Abfragen ist ...Wie eine for-Anweisung zu machen, warten mehrere mongoose Abfragen?

Danke für Ihre Hilfe.

router.get('/', function(req, res, next) { 
    Playlist.find(function (err, playlists) { 
     if (err) return next(err); 
     /* Loop through every playlists */ 
     var globalArr = []; 
     for (var increment = 0; increment < playlists.length; ++increment) 
     { 
      globalArr[increment] = []; 
      globalArr[increment]["name"] = playlists[increment].name; 
      /* Loop through every links between Songs and Playlist */ 
      PlaylistSong.find({idPlaylist: playlists[increment]._id}, function (err, songs) { 
       if (err) return next(err); 
       for (var songIncrement = 0; songIncrement < songs.length; ++songIncrement) { 
       { 
        console.log("increment"+increment); 
        globalArr[increment][songIncrement] = []; 
        /* Getting the actual song by his ID */ 
        Song.find({_id: song.idSong}, function (err, song) { 
         if (err) return next(err); 
         globalArr[increment][songIncrement]["name"] = songs[songIncrement].name; 
         globalArr[increment][songIncrement]["artist"] = songs[songIncrement].artist; 
         globalArr[increment][songIncrement]["picture"] = songs[songIncrement].picture; 
         globalArr[increment][songIncrement]["price"] = songs[songIncrement].price; 
         globalArr[increment][songIncrement]["file"] = songs[songIncrement].file; 
         globalArr[increment][songIncrement]["difficulty"] = songs[songIncrement].difficulty; 
         globalArr[increment][songIncrement]["downloaded"] = songs[songIncrement].downloaded; 
        }); 
       } 

      }}); 
     } 
     res.contentType('application/json'); 
     res.send(JSON.stringify(globalArr)); 
    }); 
}); 

Antwort

1

diese Frage sehen und die akzeptierte Antwort: Simplest way to wait some asynchronous tasks complete, in Javascript?

Es sagt im Grunde Verwenden Sie die Async module, drücken Sie alle Ihre asynchronen Funktionsaufrufe darauf und verwenden Sie dann async.parallel(), wodurch Sie einen Rückruf erhalten, wenn alle asynchronen Funktionen abgeschlossen sind.

ich es nicht getestet haben, aber so etwas wie dies scheint, wie es funktionieren könnte:

var async = require('async'); 

var calls = []; 

router.get('/', function(req, res, next) { 
    Playlist.find(function (err, playlists) { 
     if (err) return next(err); 
     /* Loop through every playlists */ 
     var globalArr = []; 
     for (var increment = 0; increment < playlists.length; ++increment) 
     { 
      (function() { 
       var i = increment; 
       calls.push(function(callback) { 
        globalArr[i] = []; 
        globalArr[i]["name"] = playlists[i].name; 
        /* Loop through every links between Songs and Playlist */ 
        PlaylistSong.find({idPlaylist: playlists[increment]._id}, function (err, songs) { 
         if (err) return next(err); 
         for (var songIncrement = 0; songIncrement < songs.length; ++songIncrement) { 
         { 
          console.log("increment"+i); 
          globalArr[i][songIncrement] = []; 
          /* Getting the actual song by his ID */ 
          Song.find({_id: song.idSong}, function (err, song) { 
           if (err) return next(err); 
           globalArr[i][songIncrement]["name"] = songs[songIncrement].name; 
           globalArr[i][songIncrement]["artist"] = songs[songIncrement].artist; 
           globalArr[i][songIncrement]["picture"] = songs[songIncrement].picture; 
           globalArr[i][songIncrement]["price"] = songs[songIncrement].price; 
           globalArr[i][songIncrement]["file"] = songs[songIncrement].file; 
           globalArr[i][songIncrement]["difficulty"] = songs[songIncrement].difficulty; 
           globalArr[i][songIncrement]["downloaded"] = songs[songIncrement].downloaded; 
          }); 
         } 
         callback(); 
        }}); 
       }); 
      })(); 
     } 
     async.parallel(calls, function(err, result) { 
      if (err) { 
       // TODO: Handle error here 
      } 
      res.contentType('application/json'); 
      res.send(JSON.stringify(globalArr)); 
     }); 
    }); 
}); 

oder wenn Sie nicht dann wollen parallel ausführen, können Sie async.series() stattdessen verwenden.

Sehen Sie diese jsFiddle für ein vereinfachtes Beispiel für Ihre Situation ... https://jsfiddle.net/bpursley/fj22hf6g/

+0

Immer noch das gleiche Problem, wenn die Funktion increment = 2 aufgerufen wird, während es 0 und dann 1 sein muss (ich habe 2 Playlisten) – Kangoo13

+0

Ich denke, es ist, weil die Schleife fertig ist, bevor die Funktionen ausgeführt werden (defered Ausführung) und Inkrement ist bereits abgeschlossen. Versuchen Sie, das Inkrement in eine lokale Variable zu verschieben und stattdessen diese Variable zu verwenden. Ich werde meine Antwort mit dem bearbeiten, worüber ich rede. – bpursley

+0

OK, ich habe das Codebeispiel aktualisiert und auch ein jsFiddle hinzugefügt, das zeigt, worum es geht. Der Trick besteht darin, einen neuen Gültigkeitsbereich zu erhalten, indem ein IIFI verwendet und eine Iteration in eine lokale Variable i eingefügt wird, so dass sie bei der nächsten Iteration nicht geändert werden kann.Ich habe auch vergessen, den Rückruf auf mein vorheriges Beispiel zu setzen (ich sagte, ich habe es nicht ausgeführt). Aber überprüfe mein Spiel und ich denke, du wirst ein einfaches Beispiel dafür sehen, was ich vorhabe. Ich glaube nicht, dass dies der EINZIGE Weg ist, um das Problem zu lösen, aber es ist ein Weg, es zu lösen. – bpursley

0

Ja, Sie sollten Async verwenden. Ich werde dies später näher erläutern (Sohn zu Bett gehen müssen ...)

PlaylistSong.statics.findSongsByPlaylistId = function(id, done) { 
 
    PlaylistSong.find({idPlaylist: id}, function(err, songs) { 
 
    if (err) { 
 
     done(err) 
 
     return 
 
    } 
 
    var getSongsFns = songs.map(function(song) { 
 
     return function(callback) { 
 
     Song.find({_id: song.idSong}, callback) 
 
     } 
 
    }) 
 
    async.parallel(getSongsFns, done) 
 
    }) 
 
} 
 

 
router.get('/', function(req, res, next) { 
 
    Playlist.find(function (err, playlists) { 
 
     if (err) return next(err); 
 
     var getSongsFns = playlists.map(function(playlist) { 
 
      return function(callback) { 
 
      PlaylistSong.findSongsByPlaylistId(playlist._id, callback) 
 
      } 
 
     }) 
 
     async.parallel(getSongsFns, function(err, songs) { 
 
      if (err) { 
 
      res.status(500).send() 
 
      return 
 
      } 
 
      res.contentType('application/json'); 
 
      res.send(JSON.stringify(songs)); 
 
     }) 
 
    }); 
 
});

+0

Nun, das ist fast, aber es ist der „Name“ Feld für die Wiedergabeliste fehlt (jede Playlist hat einen Namen), und dort isn‘ t den Feldnamen für die Lieder, wie ich die Lieder haben möchte: [hier das Ergebnis] Sie sehen? '[ [ [ { "_id": "56d006faa96d4211007e7e50", "name": "Gestresst", "__v": 0, "updated_at":„2016-02-26T08: 04: 10.649Z " "created_at": "UDT" } ], [ { "_id": "ID", "name": "Test", "__v": 0, "updated_at":" CRT“, "created_at": "UDT" } ] ], [] ]' – Kangoo13

Verwandte Themen