【问题标题】:Knexjs If not exist insert else updateKnexjs 如果不存在则插入否则更新
【发布时间】:2016-02-06 01:34:27
【问题描述】:

如何优化这段代码? 我不想调用 where 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();
        }
    });

【问题讨论】:

    标签: knex.js


    【解决方案1】:

    假设您有一个唯一键(本例中为 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' } 
    ]);
    

    【讨论】:

      【解决方案2】:

      不确定何时添加,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
        })
      

      【讨论】:

        【解决方案3】:

        刚刚修复了@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】:

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

          见:https://github.com/tgriesser/knex/issues/701

          【讨论】:

            【解决方案5】:

            如果您使用的是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(', ')
              );
            };
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2014-10-23
              • 2013-04-19
              • 2012-10-12
              • 1970-01-01
              • 1970-01-01
              • 2023-03-17
              相关资源
              最近更新 更多