2013-08-18 31 views
13

Tôi đang sử dụng Sequelize trong dự án Nodejs của mình và tôi đã tìm thấy sự cố mà tôi đang gặp khó khăn trong việc giải quyết. Về cơ bản tôi có một cron nhận được một mảng các đối tượng từ một máy chủ hơn chèn nó vào cơ sở dữ liệu của tôi như là một đối tượng (đối với trường hợp này là phim hoạt hình). Nhưng nếu tôi đã có một trong các đối tượng, tôi phải cập nhật nó.Tạo hoặc cập nhật phần tiếp theo

Về cơ bản tôi có một mảng đối tượng và có thể sử dụng phương thức BulkCreate(). Nhưng khi Cron bắt đầu lại, nó không giải quyết được nó vì vậy tôi cần một số cập nhật với một lá cờ thật sự. Và vấn đề chính: Tôi phải có một cuộc gọi lại chỉ kích hoạt một lần sau khi tất cả các lần tạo hoặc cập nhật này. Có ai có ý tưởng làm thế nào tôi có thể làm điều đó? Lặp lại trên một mảng đối tượng .. tạo hoặc cập nhật nó và sau đó nhận được một cuộc gọi lại sau?

Cám ơn sự quan tâm

Trả lời

18

Từ docs, bạn không cần phải truy vấn where để thực hiện cập nhật khi bạn có đối tượng.Ngoài ra, việc sử dụng lời hứa nên đơn giản hóa callbacks:

Thực hiện

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

Cách sử dụng

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

Note

  1. operati này trên không phải là nguyên tử
  2. tạo 2 mạng gọi

có nghĩa là nó được khuyến khích suy nghĩ lại về cách tiếp cận và có lẽ chỉ cần cập nhật các giá trị trong một cuộc gọi mạng và một trong hai:

  1. nhìn vào giá trị trả về (tức là rows_affected) và quyết định phải làm gì
  2. trả về thành công nếu hoạt động cập nhật thành công. Điều này là do tài nguyên tồn tại không thuộc trách nhiệm của dịch vụ này.
2

Sound thích bạn muốn quấn cuộc gọi Sequelize của bạn bên trong của một async.each.

+0

Tôi đã hy vọng một số tùy chọn khó chịu trên Bản cập nhật từ Phần tiếp theo nhưng có vẻ như ngoài bản đồ đường. Tôi sẽ thử cái này Cảm ơn! –

1

Điều này có thể được thực hiện với bộ phát sự kiện tùy chỉnh.

Giả sử dữ liệu của bạn nằm trong một biến được gọi là dữ liệu.

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

bạn có thể sử dụng findOrCreate và sau đó update phương pháp trong sequelize. đây là một mẫu với 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

Đây có thể là một câu hỏi cũ, nhưng đây là những gì tôi đã làm:

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

Gợi ý: Sử dụng chuỗi lời hứa để xử lý lỗi và tiết kiệm 50% mã của bạn :) –

+0

^^ Chính xác những gì tôi sắp bình luận. Nhưng bạn đã nhanh chóng. – omerjerk

6

Bạn có thể sử dụng upsert Đó là cách dễ dàng hơn.

chi tiết thực hiện:

MySQL - Thực hiện dưới dạng đĩa đơn giá trị INSERT truy vấn ON DUPLICATE KEY
cập nhật giá trị PostgreSQL - Thực hiện như một chức năng tạm thời với xử lý ngoại lệ: INSERT EXCEPTION KHI unique_constraint CẬP NHẬT
SQLite - Được thực hiện dưới dạng hai truy vấn INSERT; CẬP NHẬT. Điều này có nghĩa rằng bản cập nhật được thực hiện bất kể hàng đã tồn tại hay không

+0

Sử dụng upsert, nhưng nếu nó thực hiện một chèn, sau đó bạn sẽ cần phải sau đó nhận được đối tượng được chèn :(- http://stackoverflow.com/a/29071422/48348 –

0

Đây là một ví dụ đơn giản mà một trong hai bản cập nhật deviceID -> pushToken lập bản đồ hoặc tạo ra nó:

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

Tôi thích ý tưởng của Ataik, nhưng làm cho nó ngắn hơn một chút:

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

Cách sử dụng:

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

Tùy chọn: thêm xử lý ở đây lỗi, nhưng tôi khuyên các bạn nên chuỗi tất cả lời hứa của một yêu cầu và có một trình xử lý lỗi ở cuối.

updateOrCreate(models.NewsItem, {slug: 'sometitle1'}, {title: 'Hello World'}) 
    .then(..) 
    .catch(function(err){}); 
Các vấn đề liên quan