Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/node.js/39.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Node.JS+;猫鼬回叫地狱_Node.js_Mongodb_Asynchronous_Mongoose - Fatal编程技术网

Node.JS+;猫鼬回叫地狱

Node.JS+;猫鼬回叫地狱,node.js,mongodb,asynchronous,mongoose,Node.js,Mongodb,Asynchronous,Mongoose,如何将mongoose保存到db,但等待其他集合先加载? 平台和流派为空,因为“保存”功能在加载平台和流派之前运行,请帮助 var platforms = []; //load platforms body.release_dates.forEach(function(elem){ Platform.findOne({ id : elem.platform}, function(err, result) { platforms.push(mongoose.Type

如何将mongoose保存到db,但等待其他集合先加载? 平台和流派为空,因为“保存”功能在加载平台和流派之前运行,请帮助

var platforms = []; //load platforms
body.release_dates.forEach(function(elem){
    Platform.findOne({ id : elem.platform}, function(err, result) {
            platforms.push(mongoose.Types.ObjectId(result._id));
        });
});

var genres = []; //load genre
body.genres.forEach(function(elem){
    Genre.findOne({id: elem}, function(err, result){
        genres.push(mongoose.Types.ObjectId(result._id));
    })
});



//prepare to save!
var game = {
    igdb_id : body.id,
    name : body.name,
    summary : body.summary,
    storyline : body.description,
    genres : genres,
    platforms : platforms, // <- genres amd platforms empty and not wait platforms and genre array to complete
    release_date : body.original_release_date,
    cover : body.cover.cloudinary_id,
    videos: body.videos
};

var data = new Game(game);
data.save(function(err, game){
    if(err){
        res.send("500");
        return console.error(err);
    }

    });
}
var平台=[]//装载平台
body.release\u dates.forEach(函数(elem)){
findOne({id:elem.Platform},函数(err,result){
push(mongoose.Types.ObjectId(result.\u id));
});
});
变量类型=[]//加载类型
body.genres.forEach(函数(elem){
findOne({id:elem},函数(err,result){
tyres.push(mongoose.Types.ObjectId(result.\u id));
})
});
//准备保存!
var博弈={
igdb_id:body.id,
name:body.name,
总结:body.summary,
故事情节:body.description,
类型:类型,

平台:平台,//这是promises的一个不错的用例(这是一个非常好的工具,使您能够轻松地执行异步操作),将来应该会对您有所帮助

当前代码的问题是,
findOne
操作是异步的,会在一段时间后完成。同时,下一行将开始执行。因此,当您达到
save
状态时,
findOne
将不会完成,并且会得到空数组

实现承诺的两个流行nodejs库是和。nodejs的最新版本也实现默认值

以下是使用Bluebird的代码。基本上,您必须在平台和类型中为涉及
findOne
的每个数据库操作创建承诺。当所有这些操作完成后,您必须开始执行最后的
save
部分。这是使用等待所有承诺完成的功能实现的完成

var Promise = require('bluebird')

var platformPromises = []; //load platforms
body.release_dates.forEach(function(elem){
    platformPromises.push(new Promise(function (resolve, reject) {
        Platform.findOne({ id : elem.platform}, function(err, result) {
            if(err) 
                reject(err);
            else
                resolve(mongoose.Types.ObjectId(result._id));
        });
    }))

});

var genrePromises = []; //load genre
body.genres.forEach(function(elem){
    genrePromises.push(new Promise(function (resolve, reject) {
        Genre.findOne({id: elem}, function(err, result){
            if(err) 
                reject(err);
            else
                resolve(mongoose.Types.ObjectId(result._id));
        });
    }))

});

var allPromises = platformPromises.concat(genrePromises);

Promise.all(allPromises).then(function (result) {
    //prepare to save!

    var platforms = [];
    var genres = [];

    for(var i=0; i<platformPromises.length; i++)
        platforms.push(result[i]); // result come out in same order as the promises

    for(var i=platformPromises.length; i<result.length; i++)
        genres.push(result[i]);

    var game = {
        igdb_id : body.id,
        name : body.name,
        summary : body.summary,
        storyline : body.description,
        genres : genres,
        platforms : platforms,
        release_date : body.original_release_date,
        cover : body.cover.cloudinary_id,
        videos: body.videos
    };

    var data = new Game(game);
    data.save(function(err, game){
        if(err){
            res.send("500");
            return console.error(err);
        }

    });

})
var Promise=require('bluebird'))
var platformPromises=[];//加载平台
body.release\u dates.forEach(函数(elem)){
platformPromises.push(新承诺(函数)(解析、拒绝){
findOne({id:elem.Platform},函数(err,result){
如果(错误)
拒绝(错误);
其他的
解析(mongoose.Types.ObjectId(result._id));
});
}))
});
var genrePromises=[];//加载类型
body.genres.forEach(函数(elem){
genrePromises.push(新承诺(功能)(解析、拒绝){
findOne({id:elem},函数(err,result){
如果(错误)
拒绝(错误);
其他的
解析(mongoose.Types.ObjectId(result._id));
});
}))
});
var allPromises=platformPromises.concat(genrePromises);
承诺。所有(所有承诺)。然后(函数(结果){
//准备保存!
var平台=[];
变量类型=[];

对于(var i=0;i您可以使用异步模块来完成这项工作,它非常适合完成这类任务

    var async = require ('async');

        var platforms = [];
        var genres = [];

        async.parallel([
        function(cb){
            body.release_dates.forEach(function(elem){
                Platform.findOne({ id : elem.platform}, function(err, result){
                    cb(null,mongoose.Types.ObjectId(result._id))
                });
            });
         },
        function(cb){
            body.genres.forEach(function(elem){
                Genre.findOne({id: elem},enter code here function(err, result){
                    cb(null,mongoose.Types.ObjectId(result._id));
                })
            });
         }],function(err,results){
            //here you'll get an array of results ordered by your tasks
                if(!err){
                    platforms.push(results[0])
                    genres.push(results[1])
                }
             })
我没有运行此代码,但就是这样,如果您需要更多信息,可以阅读文档:

好的,首先,mongoose(至少是任何最新版本)如果您停止回调,则已支持承诺…其次,下面的示例使用承诺与异步功能相结合。这在Node 7+中的选项标志后面,因此您应该使用babel进行传输

我将评论放在了应该优化mongodb调用的地方,但将逻辑尽可能地放在上面,希望这对您有所帮助

关键的外卖是

  • 使用承诺,不要害怕创建额外的函数来打破逻辑
  • Promise.all可用于等待并行操作完成
  • async
    函数非常棒
代码:

//将异步将发布日期元素映射到平台
异步函数GetPlatform(发布日期){
//TODO:更改为仅包含所需属性的单个查询
返回等待承诺。全部(releaseDates.map(
elem=>Platform.findOne({id:elem.Platform})
));
}
//将您的类型列表异步映射到适当的ObjectId对象中
异步函数getGenres(genres){
//TODO:更改为在单个查询中仅返回单个属性
var genres=wait Promise.all(genres.map(elem=>Genre.findOne({id:elem}));
返回genres.map(result=>mongoose.Types.ObjectId(result.\u id));
}
//异步请求处理程序(始终将try/catch用于express)
//不确定当前/将来的版本是否允许
//处理程序/错误
异步函数saveGameDetails(req、res){
试一试{
//数组非结构化赋值,分解数组
//等待将等待承诺,承诺。所有将采取阵列
//把它们包装成一个承诺。
var[platforms,tyres]=等待承诺([
获取平台(正文发布日期),
getGenres(body.genres)
]);
//准备保存!
var博弈={
igdb_id:body.id,
name:body.name,
总结:body.summary,
故事情节:body.description,
类型:类型,

platforms:platforms,//Mongoose已经在退出回调函数时返回了承诺。感谢您指出这一点。我只是想解释一下如何为来自同步背景的人使用承诺。@hyades,很好,但是如果您要获得三个数组,您只需在“result”中混合platformPromises和genrePromises,结果是什么“for”函数看起来像是三个数组?例如,platformPromises、genrePromises、,themePromises@tonywei是,结果数组的顺序与输入数组的顺序相同,
// will asynchronously map your release date elements to the Platform
async function getPlatforms(releaseDates) {
  // TODO: change to single query with only needed properties
  return await Promise.all(releaseDates.map(
    elem => Platform.findOne({ id: elem.platform })
  ));
}

// will asynchronously map your genre list into the appropriate ObjectId objects
async function getGenres(genres) {
  // TODO: change to return only single properties in a single query
  var genres = await Promise.all(genres.map(elem => Genre.findOne({ id: elem })));
  return genres.map(result => mongoose.Types.ObjectId(result._id));
}

// asynchronous request handler (ALWAYS use a try/catch for this with express)
// not sure if current/future versions will allow for promise resulting 
// handlers/errors
async function saveGameDetails(req,res) {
  try {
    // array destructured assignment, decomposes the array
    // await will await the promise, and promise.all will take an array
    // and wrap them into a single promise.
    var [platforms, genres] = await Promise.all([
      getPlatforms(body.release_dates),
      getGenres(body.genres)
    ]);

    //prepare to save!
    var game = {
        igdb_id : body.id,
        name : body.name,
        summary : body.summary,
        storyline : body.description,
        genres : genres,
        platforms : platforms, // <- genres amd platforms empty and not wait platforms and genre array to complete
        release_date : body.original_release_date,
        cover : body.cover.cloudinary_id,
        videos: body.videos
    };

    var data = new Game(game);
    await data.save(); //already a promise, just wait for it

    // return normal result
    res.status(200).json({ success: true });
  } catch(err) {
    // generic error handler, may want to have this even more generic via express
    res.status(500).json({
      error: {
        message: err.message || 'Unknown Server Error';
      }
    })
  }
}