2013-08-18 415 views
13

我在我的Nodejs项目中使用Sequelize,我发现一个问题,我很难解决。 基本上我有一个cron从服务器获取对象数组,而不是将其作为对象插入到我的数据库中(对于这种情况是漫画)。但是如果我已经有一个对象,我必须更新它。创建或更新Sequelize

基本上我有一个对象数组,可以使用BulkCreate()方法。但是当Cron再次启动时,它不能解决它,所以我需要用upsert true标志进行某种更新。主要问题:我必须在所有这些创建或更新完成后触发一次回调。有没有人有一个想法,我该怎么做?迭代一个对象数组..创建或更新它,然后得到一个单一的回调后?

感谢您的关注

回答

18

docs,您无需查询where即可在您拥有该对象后执行更新。此外,使用的承诺应简化回调:

实施

function upsert(values, condition) { 
    return Model 
     .findOne({ where: condition }) 
     .then(function(obj) { 
      if(obj) { // update 
       return obj.update(values); 
      } 
      else { // insert 
       return Model.create(values); 
      } 
     } 
    }) 
} 

使用

upsert({ first_name: 'Taku' }, { id: 1234 }).then(function(result){ 
    res.status(200).send({success: true}); 
}); 

注意

  1. 这operati关于是不是原子
  2. 创建2网络电话

,这意味着它是明智的重新思考方法,并可能只是在一个网络呼叫更新值,并且:

  1. 看价值返回(即rows_affected)并决定要做什么
  2. 如果更新操作成功,则返回成功。这是因为资源是否存在不在该服务的责任范围内。
2

声音喜欢你想换一个async.each内你Sequelize电话。

+0

我希望在Sequelize中更新一些不安的选项,但它似乎脱离了路线图。我会试试这个。谢谢! –

1

这可以通过自定义事件发射器完成。

假设您的数据位于名为data的变量中。

new Sequelize.Utils.CustomEventEmitter(function(emitter) { 
    if(data.id){ 
     Model.update(data, {id: data.id }) 
     .success(function(){ 
      emitter.emit('success', data.id); 
     }).error(function(error){ 
      emitter.emit('error', error); 
     }); 
    } else { 
     Model.build(data).save().success(function(d){ 
      emitter.emit('success', d.id); 
     }).error(function(error){ 
      emitter.emit('error', error); 
     }); 
    } 
}).success(function(data_id){ 
    // Your callback stuff here 
}).error(function(error){ 
    // error stuff here 
}).run(); // kick off the queries 
0

您可以使用sequelize findOrCreate然后update方法。这里是async.js

async.auto({ 
    getInstance : function(cb) { 
     Model.findOrCreate({ 
     attribute : value, 
     ... 
     }).complete(function(err, result) { 
     if (err) { 
      cb(null, false); 
     } else { 
      cb(null, result); 
     } 
     }); 
    }, 
    updateInstance : ['getInstance', function(cb, result) { 
     if (!result || !result.getInstance) { 
     cb(null, false); 
     } else { 
     result.getInstance.updateAttributes({ 
      attribute : value, 
      ... 
     }, ['attribute', ...]).complete(function(err, result) { 
      if (err) { 
      cb(null, false); 
      } else { 
      cb(null, result); 
      } 
     }); 
     } 
     }] 
    }, function(err, allResults) { 
     if (err || !allResults || !allResults.updateInstance) { 
     // job not done 
     } else { 
     // job done 
    }); 
}); 
6

这可能是一个老问题的样本,但是这是我做过什么:

var updateOrCreate = function (model, where, newItem, onCreate, onUpdate, onError) { 
    // First try to find the record 
    model.findOne({where: where}).then(function (foundItem) { 
     if (!foundItem) { 
      // Item not found, create a new one 
      model.create(newItem) 
       .then(onCreate) 
       .catch(onError); 
     } else { 
      // Found an item, update it 
      model.update(newItem, {where: where}) 
       .then(onUpdate) 
       .catch(onError); 
      ; 
     } 
    }).catch(onError); 
} 
updateOrCreate(
    models.NewsItem, {title: 'sometitle1'}, {title: 'sometitle'}, 
    function() { 
     console.log('created'); 
    }, 
    function() { 
     console.log('updated'); 
    }, 
    console.log); 
+2

提示:使用承诺链接进行错误处理并保存50%的代码:) –

+0

^^我正要评论的内容正确。但你很快。 – omerjerk

6

您可以使用upsert 这是比较容易的方式。

实现细节:

MySQL的 - 实现为重复键
更新单个查询INSERT值的值的PostgreSQL - 实现为 异常处理临时函数:INSERT异常,当unique_constraint UPDATE
SQLite -作为两个查询实现INSERT; UPDATE。这意味着, 更新执行不管该行是否已经存在 或不

+0

使用upsert,但是如果它执行插入操作,则需要然后获取插入的对象:( - http://stackoverflow.com/a/29071422/48348 –

0

下面是一个简单的例子,无论是更新设备ID - > pushToken映射或创建它:

var Promise = require('promise'); 
var PushToken = require("../models").PushToken; 

var createOrUpdatePushToken = function (deviceID, pushToken) { 
    return new Promise(function (fulfill, reject) { 
    PushToken 
     .findOrCreate({ 
     where: { 
      deviceID: deviceID 
     }, defaults: { 
      pushToken: pushToken 
     } 
     }) 
     .spread(function (foundOrCreatedPushToken, created) { 
     if (created) { 
      fulfill(foundOrCreatedPushToken); 
     } else { 
      foundOrCreatedPushToken 
      .update({ 
       pushToken: pushToken 
      }) 
      .then(function (updatedPushToken) { 
       fulfill(updatedPushToken); 
      }) 
      .catch(function (err) { 
       reject(err); 
      }); 
     } 
     }); 
    }); 
}; 
6

我喜欢Ataik的想法,但做它一个短一点:

function updateOrCreate (model, where, newItem) { 
    // First try to find the record 
    return model 
    .findOne({where: where}) 
    .then(function (foundItem) { 
     if (!foundItem) { 
      // Item not found, create a new one 
      return model 
       .create(newItem) 
       .then(function (item) { return {item: item, created: true}; }) 
     } 
     // Found an item, update it 
     return model 
      .update(newItem, {where: where}) 
      .then(function (item) { return {item: item, created: false} }) ; 
    } 
} 

用法:

updateOrCreate(models.NewsItem, {slug: 'sometitle1'}, {title: 'Hello World'}) 
    .then(function(result) { 
     result.item; // the model 
     result.created; // bool, if a new item was created. 
    }); 

可选:添加的错误处理,但我强烈建议链上的所有一个请求的承诺,并在最后有一个错误处理程序。

updateOrCreate(models.NewsItem, {slug: 'sometitle1'}, {title: 'Hello World'}) 
    .then(..) 
    .catch(function(err){});