我必须创建代码以1K行的批量插入行,但是当Bookshelf / Knex库使用Promises运行代码时,我有一些错误,我需要这个循环按顺序运行(仅在之后)完成第一个SQL,第二个应该开始)。
如何使用Promises(或Rx)执行此操作?
for (var x = 0; x < parser.getCount(); x++) {
let row = parser.getRow(x);
if (_.isEmpty(row) || _.isEmpty(row.ch) || _.isEmpty(row.location)) {
break;
}
let locationData = breakDownLocation(row.location);
middleSql += `(TRIM('${row.ch}'), TRIM('${row.color}'),TRIM('${moment(row.lastUpdate, 'DD/MM/YYYY - HH:mm').format('YYYY-MM-DD HH:mm:ss')}'), TRIM('${row.mvsDescription}'), ${locationData.position === '' || _.isUndefined(locationData.position) ? 'NULL' : locationData.position}, TRIM('${locationData.row}'), TRIM('${locationData.sector}'), ${convertStatusToInt(row.status)}, ${locationData.yardId}),`;
itemsToInsert++;
if (itemsToInsert >= 1000) {
let sql = `${beginSql} ${middleSql.substring(0, middleSql.length - 1)} ${endSql}`;
bookshelf.knex.raw(sql).then(r => {
//console.log(r);
})
.catch(error => {
console.error(error);
});
middleSql = '';
itemsToInsert = 0;
}
}
答案 0 :(得分:0)
您可以使用Rx重写代码
Observable.of(parser.getCount())
.concatMap(i => {
const row = parser.getRow(i);
if (_.isEmpty(row) || _.isEmpty(row.ch) || _.isEmpty(row.location)) {
return Observable.empty();
}
const locationData = breakDownLocation(row.location);
return Observable.of(`(TRIM('${row.ch}'), TRIM('${row.color}'),TRIM('${moment(row.lastUpdate, 'DD/MM/YYYY - HH:mm').format('YYYY-MM-DD HH:mm:ss')}'), TRIM('${row.mvsDescription}'), ${locationData.position === '' || _.isUndefined(locationData.position) ? 'NULL' : locationData.position}, TRIM('${locationData.row}'), TRIM('${locationData.sector}'), ${convertStatusToInt(row.status)}, ${locationData.yardId}),`);
})
.bufferCount(1000)
.concatMap(commands => {
const middleSql = commands.join('');
const sql = `${beginSql} ${middleSql.substring(0, middleSql.length - 1)} ${endSql}`;
return bookshelf.knex.raw(sql);
});
在上面的示例中,如果批处理中出现bookshelf.knex.raw
错误,则不会提供错误处理,从而导致所有进一步处理停止。根据您的需要,您可以吞下错误或附加重试逻辑。
如果你能够使用await
这也是一个有效的选项,可以让代码更容易阅读,因为使用Rx会将程序(for..each)流程移动到更多的FP中。
答案 1 :(得分:0)
之前我曾使用Array.prototype.reduce
来完成此类事情。它看起来像这样。
const allDonePromise = someArray.reduce((previous, current) => {
return previous.then(() => {
return current.do()
})
}, Promise.resolve())
我同意使用await可以帮助你以更易读的方式做到这一点。
另一种选择是使用递归并传回先前的承诺。像。的东西。
...
const doInserts = function(i = 0, promise = Promise.resolve()) {
return promise.then(() => {
...
if (itemsToInsert >= 1000) {
...
return doInserts(i + 1, newSavesPromise)
} else {
return doInserts(i + 1, promise)
}
})
}