【问题标题】:Waterline ORM equivalent of insert on duplicate key updateWaterline ORM 相当于在重复键更新时插入
【发布时间】:2013-11-20 19:12:56
【问题描述】:

我有一个表 user_address,它有一些字段,例如

attributes: {
  user_id: 'integer',
  address: 'string' //etc.
}

目前我这样做是为了插入一条新记录,但如果该用户存在一条记录,请更新它:

UserAddress
  .query(
    'INSERT INTO user_address (user_id, address) VALUES (?, ?) ' +
      'ON DUPLICATE KEY UPDATE address=VALUES(address);',
    params,
    function(err) {
       //error handling logic if err exists
    }

有没有办法使用 Waterline ORM 而不是直接的 SQL 查询来实现相同的目标?我不想做两个查询,因为它效率低且难以维护。

【问题讨论】:

    标签: sql node.js orm sails.js waterline


    【解决方案1】:

    上面的答案不太理想。它还将该方法作为模型属性的一部分,这是不正确的行为。

    这是理想的原生解决方案的样子,它返回一个承诺,就像任何其他水线模型函数一样:

    module.exports = {
      attributes: {
        user_id: 'integer',
        address: 'string'
      },
      updateOrCreate: function (user_id, address) {
        return UserAddress.findOne().where({user_id: user_id}).then(function (ua) {
          if (ua) {
            return UserAddress.update({user_id: user_id}, {address: address});
          } else {
            // UserAddress does not exist. Create.
            return UserAddress.create({user_id: user_id, address: address});
          }
        });
      }
    }
    

    然后你可以像这样使用它:

    UserAddress.updateOrCreate(id, address).then(function(ua) {
       // ... success logic here
    }).catch(function(e) {
       // ... error handling here
    });
    

    【讨论】:

      【解决方案2】:

      使用 Waterline 查询而不是原始 SQL,创建一个自定义模型方法来执行您想要的操作。您将执行两个查询,但使用 Waterline 语法。

      下面的示例(如果您不了解延迟对象,则只需使用回调语法,但逻辑相同):

      var Q = require('q');
      
      module.exports = {
        attributes: {
          user_id: 'integer',
          address: 'string',
          updateOrCreate: function (user_id, address) {
            var deferred = Q.defer();
      
            UserAddress.findOne().where({user_id: user_id}).then(function (ua) {
              if (ua) {
                // UserAddress exists. Update.
                ua.address = address;
                ua.save(function (err) {deferred.resolve();});
              } else {
                // UserAddress does not exist. Create.
                UserAddress.create({user_id: user_id, address: address}).done(function (e, ua) {deferred.resolve();});
              }
            }).fail(function (err) {deferred.reject()});
      
          return deferred.promise;
        }
      };
      

      【讨论】:

      • Waterline 默认已经返回 bluebird 承诺。为什么要将 Q 添加到组合中?有一种更优雅的方法可以使用水线已经原生的 Promise 来做到这一点。
      • @WulfSolter 问题是关于“更新或创建”。
      • 好吧,这可能是标题,但用户确实说:“我这样做是为了插入一条新记录,但如果该用户存在一条记录,请更新它”并且 OP 的代码示例反映这。 findOrCreate 无法更新记录,如果存在且.updateOrCreate() 尚不存在,请检查#790
      • @Dário & crzrcn 抱歉!太多的深夜——我正要在我的 SailsJS 代码库中重构一些 upsert 功能,却让他们感到困惑。等不及 [PR 940] (github.com/balderdashy/waterline/pull/940) 进入 0.11
      【解决方案3】:

      @Eugene 的回答很好,但它总是会运行 2 个操作:findOne + updatecreate。我相信我们可以进一步优化它,因为如果记录存在我们只需要运行update。示例:

      module.exports = {
        attributes: {
          user_id: 'integer',
          address: 'string'
        },
        updateOrCreate: function (user_id, address) {
          return UserAddress.update({user_id: user_id}, {address: address})
          .then(function(ua){
            if(ua.length === 0){
              // No records updated, UserAddress does not exist. Create.
              return UserAddress.create({user_id: user_id, address: address});
            }
          });
        }
      }
      

      顺便说一句,有一个在水线中实现.updateOrCreate 的公开请求:#790

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2013-08-02
        • 2019-10-28
        • 2016-09-17
        • 2022-01-03
        • 1970-01-01
        • 2012-04-21
        • 2021-03-28
        相关资源
        最近更新 更多