如何在批量写入的for循环中设置async / await?

时间:2018-03-14 10:21:04

标签: javascript mongodb mongoose async-await es6-promise

出于某种原因,我找不到有关如何在for循环中设置等待的相关文章。我的想法是,我想在每500个条目中分块bulkWrite。

for循环之外的await工作正常,但是,在for循环中,我无法弄清楚如何实现它。

非常感谢。

let bulkUpdateOps = [];
let counter = 0;
let bulkWriteChunkResult = [];

for (let i = 0; i < 1000; i += 1) {
    bulkUpdateOps.push({
      updateOne: {
        filter: { _id: mongoose.Types.ObjectId(itemId) },
        update: {
          $set: { stocks: i },
        },
      },
    });

    counter += 1;

    // make bulk update in chunk of 500 items per update
    if (counter % 500 === 0) {
        Item.collection.bulkWrite(
          bulkUpdateOps,
          { ordered: true, w: 1 },
          (err, result) => {
            if (err) throw err;
            bulkWriteChunkResult.push(result);
          },
        );
      });

      console.log(bulkWriteResult);
      bulkUpdateOps = []; // re-initialize for new bulk update
    }    
}

// if update counter is not over 500 entries
if (counter % 500) {
  const bulkWriteResult = await new Promise((resolve, reject) => {
    Item.collection.bulkWrite(
      bulkUpdateOps,
      { ordered: true, w: 1 },
      (err, result) => {
        if (err) reject(err);
        resolve(result);
      }
    );
  });

  console.log(bulkWriteResult); // returns expected bulk write result
} else {
  const chunkResult = await Promise.all(bulkWriteChunkResult);
  console.log(chunkResult); // UNFORTUNATELY, this returns an empty array
}

// TODO: do something with the bulkWrite result after await

1 个答案:

答案 0 :(得分:1)

我个人认为你的目前解决方案过于复杂,但没有看到实际的代码,如果是这种情况就很难说。

首先,就我所知,你的代码并不一定要在for循环中等待,看起来你的批量写入很好,如果它们被解雇了,只是等待更新的结果

另一个复杂因素(据我可以从代码中看到)是双重检查,看看你是否已将所有项目发送到服务器。如果你的源数据是一个数组,或者可以转换的东西,那么就不需要将for循环作为双重检查。

提供的代码确实假设您的更新不会影响即将发布的更新(在两个版本中,nl,performBulkUpdateperformSyncBulkUpdate

此代码用于拆分源数组,创建批量项,然后执行操作,并保存承诺,之后等待promise.all( results )

// as long as i is smaller than the length of the array
while (i < content.length) {
  // take the amount of items, perform transformation and save the promise
  let itemsToWrite = content.slice(i, i + bulkSize ).map( transformation );
  results.push( action( itemsToWrite ) );
  // increase the index with the bulkSize
  i += itemsToWrite.length;
}

当然,如果出于某种原因,你必须等到每个写操作完成,那么你必须通过等待每个单独的写操作来改变方法,如下所示:

// as long as i is smaller than the length of the array
while (i < content.length) {
  let itemsToWrite = content.slice(i, i + bulkSize ).map( transformation );
  results.push( await action( itemsToWrite ) );
  // increase the index with the bulkSize
  i += itemsToWrite.length;
}
下面的

是一个演示两种方法的片段

// source array that must be bulkupdated
const source = [10, 5, 6, 7, 9, 15, 33, 47, 42, 63, 77, 99];

// some random action that returns a promise
const bulkWrite = (arr) => {
  return new Promise( (resolve) => {
    setTimeout( () => 
      resolve( arr.map( i => { return { id: i && i.sourceId }; } ) )
    , 100 );
  } );
};

// concat arrays together
const flatten = (arr) => arr.reduce( (current, item) => current.concat( item ), [] );

// dummy transformation suiting the write operation
const transformItem = (item) => ({ sourceId: item });

// the bulk update (default bulkSize = 3)
const performBulkChange = async ( content, action, transformation, bulkSize = 3 ) => {
  // the array containing the promises
  const results = [];
  let i = 0;
  
  // as long as i is smaller than the length of the array
  while (i < content.length) {
    // take the amount of items, perform transformation and save the promise
    let itemsToWrite = content.slice(i, i + bulkSize ).map( transformation );
    results.push( action( itemsToWrite ) );
    // increase the index with the bulkSize
    i += itemsToWrite.length;
  }
  return await Promise.all( results );
};

const performSyncBulkChange = async ( content, action, transformation, bulkSize = 3 ) => {
  // all results
  const results = [];
  let i = 0;
  
  // as long as i is smaller than the length of the array
  while (i < content.length) {
    let itemsToWrite = content.slice(i, i + bulkSize ).map( transformation );
    results.push( await action( itemsToWrite ) );
    // increase the index with the bulkSize
    i += itemsToWrite.length;
  }
  return results;
};

console.log( 'starting' );

// slower, takes at least 100 ms per bulk
performSyncBulkChange( source, bulkWrite, transformItem, 5 )
  .then( flatten )
  .then( result => console.log( result ) );

// bulk change will be faster, it doesn't wait
performBulkChange( source, bulkWrite, transformItem )
  .then( flatten )
  .then( result => console.log( result ) );