Nik*_*des 9 javascript knex.js
我想使用Knex.js执行批量更新
例如:
'UPDATE foo SET [theValues] WHERE idFoo = 1'
'UPDATE foo SET [theValues] WHERE idFoo = 2'
Run Code Online (Sandbox Code Playgroud)
值:
{ name: "FooName1", checked: true } // to `idFoo = 1`
{ name: "FooName2", checked: false } // to `idFoo = 2`
Run Code Online (Sandbox Code Playgroud)
我之前使用的是node-mysql,它允许多个语句.使用它时我只是构建了一个多语句查询字符串,只需在一次运行中通过线路发送.
我不确定如何用Knex实现同样的目标.我可以batchInsert看作我可以使用的API方法,但就任何batchUpdate问题而言都没有.
我可以进行异步迭代并分别更新每一行.这是不好的原因,这意味着从服务器到数据库将会有很多往返
我可以使用raw()Knex 的东西,可能做类似于我对node-mysql的操作.然而,这破坏了作为DB抽象层的整个knex目的(它引入了强大的DB耦合)
所以我想用"knex-y"来做这件事.
欢迎任何想法.
小智 12
我需要在事务中执行批量更新(我不想在出现问题时进行部分更新).我已经通过下一个方式解决了这个问题:
// I wrap knex as 'connection'
return connection.transaction(trx => {
const queries = [];
users.forEach(user => {
const query = connection('users')
.where('id', user.id)
.update({
lastActivity: user.lastActivity,
points: user.points,
})
.transacting(trx); // This makes every update be in the same transaction
queries.push(query);
});
Promise.all(queries) // Once every query is written
.then(trx.commit) // We try to execute all of them
.catch(trx.rollback); // And rollback in case any of them goes wrong
});
Run Code Online (Sandbox Code Playgroud)
Pat*_*ard 11
您很清楚每种方法的优缺点.我建议一个原始查询,批量更新多个异步更新.是的,您可以并行运行它们,但您的瓶颈将成为数据库运行每次更新所需的时间.细节可以在这里找到.
下面是使用knex.raw进行批量upsert的示例.假设记录是一个对象数组(我们想要更新的每一行的一个obj),其值是与要更新的数据库中的列对齐的属性名称:
var knex = require('knex'),
_ = require('underscore');
function bulkUpdate (records) {
var updateQuery = [
'INSERT INTO mytable (primaryKeyCol, col2, colN) VALUES',
_.map(records, () => '(?)').join(','),
'ON DUPLICATE KEY UPDATE',
'col2 = VALUES(col2),',
'colN = VALUES(colN)'
].join(' '),
vals = [];
_(records).map(record => {
vals.push(_(record).values());
});
return knex.raw(updateQuery, vals);
}
Run Code Online (Sandbox Code Playgroud)
这个答案很好地解释了两种方法之间的运行时关系.
编辑:
要求我展示records这个例子中的样子.
var records = [
{ primaryKeyCol: 123, col2: 'foo', colN: 'bar' },
{ // some other record, same props }
];
Run Code Online (Sandbox Code Playgroud)
请注意,如果您的record附加属性不是您在查询中指定的属性,则不能执行以下操作:
_(records).map(record => {
vals.push(_(record).values());
});
Run Code Online (Sandbox Code Playgroud)
因为您将为每个记录的查询分配太多值,并且knex将无法使每个记录的属性值与?查询中的字符匹配.您需要显式地将要插入的每个记录的值推送到数组中,如下所示:
// assume a record has additional property `type` that you dont want to
// insert into the database
// example: { primaryKeyCol: 123, col2: 'foo', colN: 'bar', type: 'baz' }
_(records).map(record => {
vals.push(record.primaryKeyCol);
vals.push(record.col2);
vals.push(record.colN);
});
Run Code Online (Sandbox Code Playgroud)
执行上述显式引用的重复方式较少,但这只是一个示例.希望这可以帮助!
假设您有给定表的有效键/值的集合:
// abstract transactional batch update
function batchUpdate(table, collection) {
return knex.transaction(trx => {
const queries = collection.map(tuple =>
knex(table)
.where('id', tuple.id)
.update(tuple)
.transacting(trx)
);
return Promise.all(queries)
.then(trx.commit)
.catch(trx.rollback);
});
}
Run Code Online (Sandbox Code Playgroud)
称呼它
batchUpdate('user', [...]);
Run Code Online (Sandbox Code Playgroud)
不幸的是,您是否受制于非常规列名?不用担心,我让你成全了:
function batchUpdate(options, collection) {
return knex.transaction((trx) => {
const queries = collection.map(tuple =>
knex(options.table)
.where(options.column, tuple[options.column])
.update(tuple)
.transacting(trx)
);
return Promise.all(queries)
.then(trx.commit)
.catch(trx.rollback);
});
}
Run Code Online (Sandbox Code Playgroud)
称呼它
batchUpdate({ table: 'user', column: 'user_id' }, [...]);
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
11124 次 |
| 最近记录: |