Knexjs如果不存在则插入else更新

时间:2015-11-05 09:27:43

标签: knex.js

如何优化此代码? 我不想在那里打电话2次......是否有可能有更好的查询?

    return self.db.clientDevices.where(device).then(function (rows) {
        if (rows.length != 1) {
            device.key = value;
            self.db.clientDevices.insert(device).then();
        } else {
            self.db.clientDevices.where(device).update(device).then();
        }
    });

5 个答案:

答案 0 :(得分:3)

不确定是什么时候添加的,knex 现在有一个 onConflict 方法:http://knexjs.org/#Builder-merge。我以这种方式编写了一个“upsert”函数,它似乎与 mysql 一起工作正常:

module.exports = (table, idKey, data) => require('../knex')(table)
  .insert(data)
  .onConflict(idKey)
  .merge()
  .catch( err => {
    console.error(`There was an error upserting the "${table}" table by ${idKey}:`, err)
    throw err
  })

答案 1 :(得分:2)

使用原始sql尝试ON DUPLICATE KEY UPDATE,因为knex现在不支持此功能。

请参阅:https://github.com/tgriesser/knex/issues/701

答案 2 :(得分:2)

假设您有一个唯一键(在此示例中为 post_id )和一个对象数组( blogPosts ),则可以使用以下帮助方法:

function insertOrUpdate(tableName, blogPosts){
    return knex.transaction(trx => {
        let queries = blogPosts.map(tuple =>
          trx.raw(util.format('%s ON CONFLICT (post_id) DO UPDATE SET %s',
            trx(tableName).insert(tuple).toString().toString(),
            trx(tableName).update(tuple).whereRaw(`'${tableName}'.post_id = '${tuple.post_id}'`).toString().replace(/^update\s.*\sset\s/i, '')
          ))               
          .transacting(trx)
        );
        return Promise.all(queries).then(trx.commit).catch(trx.rollback);
    })
}

并这样调用它:

insertOrUpdate('posts', [ 
    { post_id : 1, content: 'Blog Post 1' },
    { post_id : 2, content: 'Blog Post 2' } 
]);

答案 3 :(得分:2)

只需修复@Sebyddd正则表达式,删除格式并将逻辑从“ ON CONFLICT”更改为“ ON DUPLICATE KEY UPDATE”: https://gist.github.com/hinex/017c7c98c4a163d766fe2191a65fd944

const insertOrUpdate = (tableName, rows) => {

    return DB.transaction((trx) => {

        const queries = rows.map((tuple) => {

            const insert = trx(tableName).insert(tuple).toString()
            const update = trx(tableName).update(tuple).toString().replace(/^update(.*?)set\s/gi, '')

            return trx.raw(`${insert} ON DUPLICATE KEY UPDATE ${update}`).transacting(trx)
        })

        return Promise.all(queries).then(trx.commit).catch(trx.rollback)
    })
}

答案 4 :(得分:0)

如果您使用的是PostgreSQL,因为没有ON DUPLICATE KEY UPDATE。因此,在PostgreSQL中,您应该使用ON CONFLICT ("id") DO UPDATE SET

const insertOrUpdate = (knex, tableName, data) => {
  const firstData = data[0] ? data[0] : data;

  return knex().raw(
    knex(tableName).insert(data).toQuery() + ' ON CONFLICT ("id") DO UPDATE SET ' +
      Object.keys(firstData).map((field) => `${field}=EXCLUDED.${field}`).join(', ')
  );
};

如果您使用Objection.js(knex的包装器),那么(在这种情况下,请不要忘记导入knex):

const insertOrUpdate = (model, tableName, data) => {
  const firstData = data[0] ? data[0] : data;

  return model.knex().raw(
    knex(tableName).insert(data).toQuery() + ' ON CONFLICT ("id") DO UPDATE SET ' +
      Object.keys(firstData).map((field) => `${field}=EXCLUDED.${field}`).join(', ')
  );
};