如何在书架中批量“upsert”?

时间:2017-08-01 09:09:01

标签: node.js knex.js bookshelf.js

我需要将CSV文件(大约20K行)中的数据导入我的数据库。某些行可能已存在于数据库中,因此只需要更新它们,但必须插入新行。如果任何操作失败,则必须取消该交易。

我该怎么做?这是我正在使用的代码:

num_threads

此代码位于for循环中,但在第二次迭代中失败,可能是因为var vehicle = { id: row.id, lastUpdate: moment(row.lastUpdate, 'DD/MM/YYYY - HH:mm').toDate(), version: row.version, color: row.color, location: row.location, status: row.status }; Vehicle.forge({ id: row.id }) .save(vehicle, { transacting: t, patch: true }) .then(model => { console.log('*************' + vehicle.id); }) .catch(Vehicle.NoRowsUpdatedError, err => { // There are no rows for this chassis, so let's insert it Vehicle.forge(vehicle) .save(null, { transacting: t, method: 'insert' }) .then(model => { console.log('++++++++++++++' + vehicle.id); }) .catch(err => { console.log(`INSERT ERROR: ${err.message}`); t.rollback(); return res.json({ status: false, count: 0, error: err.message }); }); }) .catch(err => { console.log(`UPDATE ERROR: ${err.message}`); t.rollback(); return res.json({ status: false, count: 0, error: err.message }); }); 之间的并发性。

我还尝试将自定义函数添加到我的模型文件中,但它说该函数不存在。

promises

1 个答案:

答案 0 :(得分:2)

您可以直接使用knex来代替使用书架。只需抓住传递给书架的knex实例,就可以像这样使用它:

knex.transaction((trx) => {
  return Bluebird.map(vehicles, vehicle => {
    const insert = knex('vehicles').insert(vehicle).toString();
    delete vehicle.id;
    const update = knex('vehicles').update(vehicle).toString();
    const set = update.substring(18);
    return trx.raw(`${insert} ON CONFLICT (id) DO UPDATE ${set}`);
  });
});

我们可以利用Knex的方便toString方法为我们生成大部分原始查询;通过这种方式,我们可以做一个upsert,即使它没有Knex直接支持。 Bluebird的map函数非常适合干净地处理这样的数据数组,并且可以让你等待完全遍历它。