【问题标题】:Node.js callback unexpected behaviour with Mongoose使用 Mongoose 的 Node.js 回调意外行为
【发布时间】:2017-01-10 02:01:05
【问题描述】:

我是一个 nodejs 初学者,我遇到了一些我不理解的回调行为。我正在使用 Express 路由器使用 POST 请求将 Mongoose 对象写入 Mongodb。在请求的正文中,我传递了一个包含两个字段的嵌套 json 结构 - jobDetailsexamplesjobDetails 中的数据用于创建Job Mongoose 对象,examples 中的数据用于创建多个Example Mongoose 对象。 JobExample 对象链接在一起,Job 在其中一个字段中包含Example 对象的列表。

我尝试实现这一点的方式是通过以下方式使用回调。基本上,我首先将Job 对象保存到mongo,然后遍历示例——每次创建一个Example 对象并通过.job 字段将其链接到作业,并将Example 对象保存到mongo。然后在Example对象保存函数的回调中,我用新的Example对象更新了Job对象,并将更新后的版本保存到mongo。

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

这并没有像我预期的那样执行。具体来说,实际上将两倍数量的示例保存到 mongo 中,其中有几个重复和一些丢失。我知道回调是异步的,但对我来说,这仍然无法解释为什么要保存两倍的示例数量,有些会重复,有些会丢失。

我最终通过以下方式让它正常工作,根本不使用回调。

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

我也不确定这是否是最佳解决方案。但我想知道为什么我原来的方法会导致意外行为。

【问题讨论】:

    标签: node.js mongodb express mongoose callback


    【解决方案1】:

    这应该可行..

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

    【讨论】:

    • 您确定 `job.save(function(err, job) { if (!err) job.examples = []; });` 部分吗?这不是把所有的例子都清楚了吗?
    • 它对你有用吗?此行在保存后删除了每个示例,这意味着它不会添加重复项。
    • 但所有示例都必须保存在 job.examples 中。如果在每个job.save之后清除示例,它不会覆盖之前保存的所有示例吗?
    • 正如我所见,这并没有删除所有示例,它只是在每次迭代中重新初始化当前作业对象的示例,而不是所有示例,因此您的所有示例都会添加。它不会覆盖,因为您的每次迭代都是集合中的新对象
    【解决方案2】:

    我建议您使用像 async 这样的库来逐步执行此类保存操作。遵循这种方法以获得更好的代码可读性和更好的结果

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

    使用这种方法,您只需在所有其他操作完成后调用作业的保存函数一次。如果在任何时候触发错误,则整个流程都会停止。有关异步库的更多信息,请参阅this

    【讨论】:

      猜你喜欢
      • 2011-09-22
      • 1970-01-01
      • 2014-11-19
      • 2017-04-06
      • 1970-01-01
      • 2010-12-24
      • 2021-08-28
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多