2013-08-18 117 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){});