如何使for语句等待多个mongoose查询?

时间:2016-04-22 19:06:16

标签: node.js mongodb asynchronous mongoose

我目前要做的是显示包含歌曲的所有播放列表。要做到这一点,我首先找到每个播放列表,然后我做一个for循环遍历它们(同时我初始化globalArr并放置值然后它将被发送为json,因为它是一个API)和问题当我在循环中找到另一个(PlaylistSong.find或Song.find)时,因为它是异步的,当for将结束时我将得到0,因为它们将取值当increment达到最大值时async。我听说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)); }); }); ,我甚至用Google搜索,但我真的不明白如何通过这段代码,因为它是for循环和异步查询的组合...

感谢您的帮助。

{{1}}

2 个答案:

答案 0 :(得分:1)

请参阅此问题和接受的答案: Simplest way to wait some asynchronous tasks complete, in Javascript?

它基本上说要使用Async module,将所有异步函数调用推送到它上面然后使用async.parallel(),这会在所有异步函数完成时给你一个回调。

我还没有对它进行过测试,但这样的事情看起来似乎有用了:

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));
        });
    });
});

或者如果您不想并行执行,则可以使用async.series()代替。

有关您的情况的简化示例,请参阅此jsFiddle ... https://jsfiddle.net/bpursley/fj22hf6g/

答案 1 :(得分:0)

是的,你应该使用异步。我稍后会详细解释(儿子必须上床......)

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));
        }) 
    });
});