Javascript 使用Mongoose保存多个文档,并在保存最后一个文档时执行某些操作

Javascript 使用Mongoose保存多个文档,并在保存最后一个文档时执行某些操作,javascript,mongodb,mongoose,jasmine,Javascript,Mongodb,Mongoose,Jasmine,我想使用Mongoose将8个对象保存到MongoDB数据库。保存最后一个文档时,我希望报告(即发送事件)所有文档都已保存 我现在的做法相当混乱(尤其是对于我想要保存的文档数量越来越多的情况) 这就是我现在拥有它的方式(在这个例子中只针对4个人)。你能推荐一种更干净的方法吗 person1.save(function(err, result){ if (err) console.log(err); else{ person2.save(function(err,

我想使用Mongoose将8个对象保存到MongoDB数据库。保存最后一个文档时,我希望报告(即发送事件)所有文档都已保存

我现在的做法相当混乱(尤其是对于我想要保存的文档数量越来越多的情况)

这就是我现在拥有它的方式(在这个例子中只针对4个人)。你能推荐一种更干净的方法吗

person1.save(function(err, result){
    if (err) console.log(err);
    else{
        person2.save(function(err, result){
            if (err) console.log(err);
            else{
                person3.save(function(err, result){
                    if (err) console.log(err);
                    else{
                        person4.save(function(err, result){
                            if (err) console.log(err);
                            else{
                                done();
                            }
                        });
                    }
                });
            }
        });
    }
});
我将使用它来迭代一组人员模型。这将使您的代码更干净,并有助于避免您在代码中遇到的问题

从:

.each(列表,迭代对象,[context])别名:forEach

迭代元素列表,依次生成一个iteratee函数。如果传递了上下文对象,则iteratee将绑定到上下文对象。每次调用iteratee都使用三个参数进行调用:(元素、索引、列表)。若列表是一个JavaScript对象,迭代对象的参数将是(值、键、列表)。返回用于链接的列表

例如:

var people = [person1, person2];
var length = people.length;
var hasError = false;

var doSomething =  function() {
    console.log("I'm done");
}

var doSomethingElse =  function() {
    console.log('There was an error');
}

_.each(people, function(person, i) {

    if (!hasError) {

        person.save(function(err, result) {
            if (err) {
                console.log(err);
                hasError = true;
            }
        );

        if (i === length) {
            doSomething();
        }

    } else {

        // There was an error
        doSomethingElse();
    }

});

我建议使用数组并使用迭代保存。将具有相同的性能,但代码将更干净

你可以

var Person = mongoose.model('Person');
var people = [];

people[0] = new Person({id: 'someid'});
people[0].set('name', 'Mario');
people[1] = new Person({id: 'someid'});
people[1].set('name', 'Mario');
people[2] = new Person({id: 'someid'});
people[2].set('name', 'Mario');

var errors = [];
for(person in people){
 people[person].save(function(err, done){
  if(err) errors.push(err);
  if (person === people.length){ yourCallbackFunction(errors){
    if (errors.length!=0) console.log(errors);
    //yourcode here
   };
  }
 });
}

一个用于协调异步操作的有用库是。在您的情况下,代码如下所示:

var people = [ person1, person2, person3, person4, ... ];

async.eachSeries(people, function(person, asyncdone) {
  person.save(asyncdone);
}, function(err) {
  if (err) return console.log(err);
  done(); // or `done(err)` if you want the pass the error up
});

最好的方法是使用异步。 部分代码片段可能如下所示。请参考以上链接。 它打破了异步的本质,转换成一个接一个的进程(如果我没有错的话)


使用promises和Array.map()


但有一点不同:您的代码同时保存文档,而原始示例按顺序保存文档。在请求描述中,作者没有提到此顺序很重要,但我更新了ans以查看是否所有操作都很好。@PawełSmołka我想是否同时保存并不重要,我只想知道最后一个人什么时候被保存。当最后一个人被保存并完成时,这将触发,但不考虑是否所有人都已完成保存。只有async会正确计算所有已完成的保存。感谢您的提示,删除了
else
,现在应该可以了。这将在启动X个保存操作时调用回调,但这并不一定意味着它们都已完成。另外,为什么不直接使用
Array#forEach
?请参阅我关于操作完成的更新答案。为了回答您关于下划线的问题,我更喜欢下划线。与普通javascript循环相比,每种方法都方便、简单/可读。我看不出
每种方法(Array,fn)之间有多大区别
array.forEach(fn)
我自己(实际上我觉得第二个更可读)上面的帖子不能保证save()适用于第一条评论中提到的所有情况。这种解决方案需要额外的库,这会使应用程序更沉重。还是很好的解决方案。我认为,异步库不是一个主要的补充。另外,由于这是服务器端,async的值与它的占用空间比较小,对代码并没有什么负面影响。对于类似的情况,您实际上希望使用并行方法。@DanSabin最初的问题显示了一个顺序工作流,我使用
async
复制了该工作流,但我也会使用并行方法(或者可能是
eachLimit
)我在哪里实现此代码?我尝试将其粘贴到我的控制器上。它给了我
person.save不是一个函数
 waterfall([
    function(callback){
 callback(null, 'one', 'two');
},
   function(arg1, arg2, callback){
    callback(null, 'three');
  },
  function(arg1, callback){
 // arg1 now equals 'three' 
  callback(null, 'done');
  }
], function (err, result) {
  // result now equals 'done' 
});
const userPromises = persons.map(user => {
  return new Promise((resolve, reject) => {
    person.save((error, result) => {
      if (error) {
        reject(error)
      }
      resolve(result);
    })
  })
});

Promise.all(userPromises).then((results) => {
  //yay!
  //results = [first, second, etc...]
}, (error) => {
  //nay!
})