2016-09-02 63 views
-1

我是一个nodejs初学者,遇到了一些我不明白的回调行为。我正在使用Express路由器使用POST请求将Mongoose对象写入Mongodb。在请求的主体中,我传递了嵌套的json结构,其中包含两个字段 - jobDetailsexamplesjobDetails中的数据用于创建一个Job Mongoose对象,examples中的数据用于创建若干个Example Mongoose对象。 JobExample对象链接,因为Job包含其中一个字段中的Example对象的列表。Node.js与Mongoose发生意外行为

我试图实现这一点的方式是用以下方式回调。基本上我首先将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); 
     }); 
    } 
}); 

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

回答

0

这应该工作..

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

你确定了'job.save(函数(ERR,作业){ 如果(ERR) job.examples = [];! });'一部分?这不仅仅是清楚所有的例子吗? – user1893354

+0

它适合你吗? 此行在保存后删除了每个示例,这意味着它不会添加重复项。 – abdulbarik

+0

但所有的例子都必须保存在job.examples中。如果在每个job.save之后清除示例,是不是会覆盖之前保存的所有示例? – user1893354

0

我会建议你使用一个库像异步在一步步地保存操作执行这样。按照这种方法进行的代码更好的可读性和更好的结果

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