forEach与NodeJS和Async

时间:2018-04-11 09:27:23

标签: node.js express foreach

我是NodeJS(Express)的新手。我正在尝试构建一个API,列出酒店的“房间”,以及每个房间的“照片”。

我想做的是: - 获取酒店所有客房的清单 - 循环浏览此房间列表并添加照片 - 返回带有房间和照片的JSON

我的问题是我似乎无法将“照片”结果附加到“房间结果”。

async.waterfall([

    //  Function 1
    function(callback) {

        //  Find all Hotel Rooms
        Room.find({ 'hotel': req.params.hotel_id})
        .exec(function(err, rooms) {                
            callback(null, rooms);  // Send rooms to function 2
        });

    },
    //  Function 2
    function(rooms, callback) {             

        //  Loop through each room to get photos for each room
        rooms.forEach(function(room) {          

            //  Get photos for room
            RoomPhoto.find({ 'room': room._id})             
            .exec(function(err, photos) {   

                // I want to add these "photos" to the main "rooms" object, but attached to each individual "room"
                room.photos = JSON.stringify(photos);

            });

        })

        console.log(rooms)
        callback(null, rooms);
    }

], function(err, results) {

    if(err) console.log('err');
    res.json(results);

});

任何帮助都会非常感激,因为我已经花了好几个小时试图解决它。

由于

我已将我的脚本更新为此,但“照片”仍未进入最终的“房间”对象。我已经包含了代码以及控制台输出。

代码:

exports.index = function(req, res, next) {  

    Room.find({ 'hotel': req.params.hotel_id})
    .exec(function(err, rooms) {

        async.each(rooms, function(room, room_cb) {

            console.log('Room Name: ' + room.name);

            RoomPhoto.find({ 'room': room._id})
            .exec(function(err, photos) {

                console.log('Photos: ' + photos);

                room.photos = photos; 
                // photos should now be in the main "rooms" object right??
                // I can console.log the photos here to prove they exists
                room_cb();
            });

        }, function(err) {

            if(err) {
                console.log('Error: ' + err)
            }
            else {
                // But the photos are not in the final "rooms" object
                console.log('FINAL ROOMS OBJECT, why are the photos not here??');
                console.log(rooms);
                res.json(rooms);
            }
        })      
    });
};

以下是上述脚本的控制台输出:

  

房间名称:测试室1

     

房间名称:测试室2

     

照片:

{ _id: 5acd3094e0026f38ca4b44bc,
  src: 'https://picsum.photos/200/300/?image=252',
  room: 5acd3094e0026f38ca4b44bb,
  __v: 0 }
     

照片:

{ _id: 5acd30c8cec87777eefcd32d,
  src: 'https://picsum.photos/200/300/?image=252',
  room: 5acd30c8cec87777eefcd32c,
  __v: 0 }
     

最终房间对象

[ { _id: 5acd3094e0026f38ca4b44bb,
    name: 'Test Room 1',
    hotel: 5accd4e1734d1d55c3195c84,
    __v: 0 },
  { _id: 5acd30c8cec87777eefcd32c,
    name: 'Test Room 2',
    hotel: 5accd4e1734d1d55c3195c84,
    __v: 0 } ]

4 个答案:

答案 0 :(得分:4)

由于函数RoomPhoto也是异步的,因此您需要等到所有照片都加载后再调用回调函数。像那样:

//  Function 2
function(rooms, callback) {             
    // https://caolan.github.io/async/docs.html#each
    //  Loop through each room to get photos for each room
    async.each(rooms, function(room, room_cb) {          
        //  Get photos for room
        RoomPhoto.find({ 'room': room._id})             
        .exec(function(err, photos) {   
            room.photos = JSON.stringify(photos)
            room_cb()
        });
    }, function (err) {
        console.log(rooms)
        callback(null, rooms)
    })
}

答案 1 :(得分:0)

由于您是node.js的新用户,您可能不了解最新标准以及您可以使用的内容。以下是如何在不包含async模块的情况下完成此任务... < / p>

const requestHandler = async (req, res, next) => {

    let rooms = await Room.find({ 'hotel': req.params.hotel_id})
        .exec()
        .catch(err => { 
            console.log(err);
            throw err;
        });

        //  Get photos for room
    let photos = await Promise.all(rooms.map(
        room => RoomPhoto.find({ 'room': room._id})
        .catch(err => { 
            console.log(err);
            throw err;
        });
    ))

    rooms = rooms.map((room, index) => {
         room = room.toObject();
         room.photos = JSON.stringify(photos[index]);
         return room;
    });
// Now your "rooms" array will have room objects, with photos populated.
    res.send(rooms);
});

要导出它,您可以这样做:

module.exports.index = requestHandler;

答案 2 :(得分:0)

我找到了有效的东西...... 出于某种原因,MongoDB“_id”导致了问题。

exports.index = function(req,res,next){

Room.find({ 'hotel': req.params.hotel_id})
.exec(function(err, rooms) {

    rooms = JSON.parse(JSON.stringify(rooms).replace(/_id/g,"room_id"));    

    console.log(rooms);
    console.log('---------------------------');

    async.each(rooms, function(room, room_cb) {         

        RoomPhoto.find({ 'room': room.room_id})
        .exec(function(err, photos) {

            console.log('Room: ' + room.id);
            console.log('Photos: ' + photos);

            room.photos = photos;
            //console.log('Photos: ' + rooms[key].photos);

            room_cb(); 
        });

    }, function(err) {

        if(err) {
            console.log('Error: ' + err)
        }
        else {
            console.log('FINAL ROOMS OBJECT');

            rooms = JSON.parse(JSON.stringify(rooms).replace(/room_id/g,"_id"));                

            console.log(rooms);
            res.json(rooms);
        }
    })      
});

};

答案 3 :(得分:-1)

尝试在callback(null, rooms);行下方放置第二条room.photos = JSON.stringify(photos);行(靠近末尾的行)。

由于JavaScript的异步特性,它可能会在您的查询完成获取照片之前运行。

您可能还想添加一些支票,以防房间没有照片。