4

我有一个表 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 查询来实现同样的事情?我不想做两个查询,因为它效率低且难以维护。

4

3 回答 3

7

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

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

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
});
于 2015-03-11T18:09:32.933 回答
4

使用 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;
  }
};
于 2014-01-20T21:35:56.610 回答
4

@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

于 2015-06-04T00:06:50.243 回答