如何在保存另一个文档之前等待循环完成?

时间:2019-05-07 09:57:05

标签: javascript node.js mongodb mongoose

问题

我正在使用for循环来创建和保存多个文档,然后将其ID推入对另一个文档的引用,稍后我将尝试保存。

但是,当我执行代码时,最终文档保存发生在for循环之前,这意味着引用永远都不会保存。

如何在保存另一个文档(在我的情况下为条目)之前完成for循环?还是有一种完全不同的更好的方式来完成我要完成的工作?

我尝试过的

我尝试将代码分成两个异步等待函数,还尝试将代码分为一个带有回调的函数,该回调在完成后会调用另一个函数。我目前正在尝试更深入地理解Promises。我还在探索是否可以设置标志或稍稍延迟时间。

    Template.findById(templateId, function (err, template) {

        if (err) { return console.log(err) }

        let entry = new Entry();
        entry.entryState = "Draft";
        entry.linkedTemplateId = template._id;

        for (var i = 0; i < template.components.length; i++) {

            let component = template.components[i]

            let entryComp = new entryComponent({
                componentOrder: component.componentOrder,
                componentType: component.componentType,
                templateComponentId: component._id,
                entryId: entry._id
            })

            entryComp.save(function(err){
                if (err) { return console.log(err) }
                entry.entryComponents.push(entryComp._id);
            });

        }

        entry.save(function(err){
            if (err) { return console.log(err) }
        });
    })

2 个答案:

答案 0 :(得分:1)

我喜欢为此目的使用递归。尽管我非常确信别人已经在我之前想到了这一点,但是我还是自己发现了这种解决方案。由于我是自己解决这个问题的,因此我不确定这是否是最好的处理方法。但是我已经使用了它,并且它在我的应用程序中很好地工作。

   Template.findById(templateId, function (err, template) {

    if (err) { return console.log(err) }

    let entry = new Entry();
    entry.entryState = "Draft";
    entry.linkedTemplateId = template._id;

    var fsm = function(i){
        if (i<template.components.length)
        {
            let component = template.components[i]

            let entryComp = new entryComponent({
            componentOrder: component.componentOrder,
            componentType: component.componentType,
            templateComponentId: component._id,
            entryId: entry._id
            })

            entryComp.save(function(err){
                if (err) { return console.log(err) }
                entry.entryComponents.push(entryComp._id);

                    //cause the fsm state change when done saving component
                     fsm(i+1)
                });


        }

        else
        {
            //the last index i=length-1 has been exhausted, and now i= length, so
            //so do not save a component, instead save the final entry 
           entry.save(function(err){
                if (err) { return console.log(err) }
                }); 

        }
    }

    //start the fsm
    fsm(0)

})

简而言之,我将使用递归来解决问题。但是,如果组件的数组很大,则可能会超出递归堆栈限制。考虑限制此应用程序中允许的项目数量。

答案 1 :(得分:1)

您可以在javascript中使用新的“ for of”循环以及异步等待来简化答案:-

 Template.findById(templateId, async function (err, template) {

  try {
      if (err) { return console.log(err) }

        let entry = new Entry();
        entry.entryState = "Draft";
        entry.linkedTemplateId = template._id;

        for(const component of template.components) {
          let entryComp = new entryComponent({
                componentOrder: component.componentOrder,
                componentType: component.componentType,
                templateComponentId: component._id,
                entryId: entry._id
            })

          await entryComp.save();
          entry.entryComponents.push(entryComp._id);
        }

          await entry.save();
  } catch (error) {
    // handle error
  }
})

另一种方法是通过Promise.all使用常规的“ for循环”,这将比另一种更快,因为您无需再等待一个entryComp的保存就可以了:-

 Template.findById(templateId, async function (err, template) {

  try {
      if (err) { return console.log(err) }

        let entry = new Entry();
        entry.entryState = "Draft";
        entry.linkedTemplateId = template._id;

        const promises = [];

         for (var i = 0; i < template.components.length; i++) {

            let component = template.components[i]

            let entryComp = new entryComponent({
                componentOrder: component.componentOrder,
                componentType: component.componentType,
                templateComponentId: component._id,
                entryId: entry._id
            })

            promises.push(entryComp.save());
            entry.entryComponents.push(entryComp._id);
        }

        await Promise.all(promises);

          await entry.save();
  } catch (error) {
    // handle error
  }
})

此外,如果您要执行相互依赖的多文档操作,则执行这些操作的正确方法是通过mongodb事务处理,这将提供原子性。在这里https://docs.mongodb.com/master/core/transactions/

看看