node.js - 如何批量删除书架中的 "upsert"?

标签 node.js knex.js bookshelf.js

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

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

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 });
                    });

此代码位于 for 循环中,但在第二次迭代中失败,可能是因为 promise 之间存在并发。

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

let bookshelf = require('./base');

var Vehicle,
    Vehicles;

Vehicle = bookshelf.Model.extend({
    tableName: 'vehicles',

    /**
     * Insert a model based on data
     * @param {Object} data
     * @param {Object} [options] Options for model.save
     * @return {Promise(bookshelf.Model)}
     */
    create: function (data, options) {
        return this.forge(data).save(null, options);
    },

    /**
     * Select a model based on a query
     * @param {Object} [query]
     * @param {Object} [options] Options for model.fetch
     * @param {Boolean} [options.require=false]
     * @return {Promise(bookshelf.Model)}
     */
    findOne: function (query, options) {
        options = extend({ require: true }, options);
        return this.forge(query).fetch(options);
    },

    /**
     * Select a model based on data and update if found, insert if not found
     * @param {Object} selectData Data for select
     * @param {Object} updateData Data for update
     * @param {Object} [options] Options for model.save
     */
    upsert: function (selectData, updateData, options) {
        return this.findOne(selectData, extend(options, { require: false }))
            .bind(this)
            .then(function (model) {
                return model
                    ? model.save(
                        updateData,
                        extend({ patch: true, method: 'update' }, options)
                    )
                    : this.create(
                        extend(selectData, updateData),
                        extend(options, { method: 'insert' })
                    )
            });
    }
});

Vehicles = bookshelf.Collection.extend({
    model: Vehicle
});

module.exports = {
    Vehicle: bookshelf.model('Vehicle', Vehicle),
    Vehicles: bookshelf.collection('Vehicles', Vehicles)
};

最佳答案

您可以直接使用 knex 来完成此操作,而不是使用书架。只需获取传递给 bookshelf 的 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 方法为我们生成大部分原始查询;这样,即使 Knex 不直接支持,我们也可以进行更新插入。 Bluebird 的 map 函数非常适合干净地处理这样的数据数组,并且可以让您等待完全循环它。

关于node.js - 如何批量删除书架中的 "upsert"?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45433593/

相关文章:

javascript - 如何使用变量字段名增加mongodb字段?

javascript - 在 JavaScript 中实现 monad

database - 在不丢失数据的情况下更新 Knex.js 表

javascript - 包版本更改时如何通知?

javascript - 使用 lodash 仅使用键查找数组中的差异

javascript - 使用书架查询

Knex.js - 外键约束形成不正确

mysql - 如何使用 knex/Bookshelf 选择数据库表达式作为值

orm - 一旦模型定义,如何建立 bookshelf.js 关系?

mysql - ER_CON_COUNT_ERROR : Too many connections knex and bookshelf