水线ORM等效插入重复键更新

我有一个表user_address,它有一些像这样的字段

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

目前我正在做这个插入一个新的logging,但如果这个用户存在,更新它:

 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 } 

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

做一个自定义模型的方法,你想要什么使用水线查询不是原始的SQL。 您将执行两个查询,但使用Waterline语法。

下面的例子(如果你不知道延迟对象,那么只使用callback语法,但逻辑是相同的):

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

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

这里是理想的本地解决scheme看起来像返回一个承诺,就像任何其他水线模型函数将:

 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个操作: findOne + updatecreate 。 我相信我们可以进一步优化它,因为如果logging存在,我们只需要运行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