出于某种原因,我找不到有关如何在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
答案 0 :(得分:1)
我个人认为你的目前解决方案过于复杂,但没有看到实际的代码,如果是这种情况就很难说。
首先,就我所知,你的代码并不一定要在for循环中等待,看起来你的批量写入很好,如果它们被解雇了,只是等待更新的结果
另一个复杂因素(据我可以从代码中看到)是双重检查,看看你是否已将所有项目发送到服务器。如果你的源数据是一个数组,或者可以转换的东西,那么就不需要将for循环作为双重检查。
提供的代码确实假设您的更新不会影响即将发布的更新(在两个版本中,nl,performBulkUpdate
和performSyncBulkUpdate
)
此代码用于拆分源数组,创建批量项,然后执行操作,并保存承诺,之后等待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 ) );