2013-08-18 14 views
13

Uso Sequelize nel mio progetto Nodejs e ho riscontrato un problema che ho difficoltà a risolvere. Fondamentalmente ho un cron che ottiene una matrice di oggetti da un server che lo inserisce nel mio database come oggetto (per questo caso, cartoni animati). Ma se ho già uno degli oggetti, devo aggiornarlo.Creazione o aggiornamento Sequenza

Fondamentalmente ho una matrice di oggetti e a potrebbe usare il metodo BulkCreate(). Ma come il Cron ricomincia, non lo risolve quindi avevo bisogno di una sorta di aggiornamento con una bandiera vera e propria. E il problema principale: devo avere una richiamata che si attiva solo una volta dopo tutte queste creazioni o aggiornamenti. Qualcuno ha un'idea di come posso farlo? Esegui un iter su una serie di oggetti ... creandoli o aggiornandoli e ottenendo successivamente una singola callback?

Grazie per l'attenzione

risposta

18

Dalla docs, non è necessario interrogare where per eseguire l'aggiornamento una volta ottenuto l'oggetto.Inoltre, l'uso della promessa dovrebbe semplificare le richiamate:

attuazione

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

Uso

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

Nota

  1. questo operati on non è atomica
  2. crea 2 reti chiama

che significa che è consigliabile ripensare l'approccio e, probabilmente, solo aggiornare i valori in una chiamata di rete e:

  1. sguardo al valore restituito (es rows_affected) e decidere cosa fare
  2. restituire un successo se l'operazione di aggiornamento ha esito positivo. Ciò è dovuto al fatto che l'esistenza della risorsa non rientra nella responsabilità di questo servizio.
2

suono ama si desidera avvolgere le chiamate Sequelize all'interno di un async.each.

+0

Speravo in qualche opzione sconvolta sull'aggiornamento da Sequelize ma sembra fuori dalla mappa stradale. Ci proverò. Grazie! –

1

Questo può essere fatto con l'emettitore di eventi personalizzato.

Supponendo che i dati siano in una variabile denominata dati.

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

è possibile utilizzare findOrCreate e poi update metodi in sequelize. Ecco un esempio con 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

Questa potrebbe essere una vecchia questione, ma questo è quello che ho fatto:

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

Suggerimento: utilizza il concatenamento promesso per la gestione degli errori e salva il 50% del codice :) –

+0

^^ Esattamente quello che stavo per commentare. Ma eri veloce. – omerjerk

6

È possibile utilizzare upsert E 'modo più semplice.

modalità d'attuazione:

MySQL - implementato come un unico valori query di inserimento ON DUPLICATE KEY
aggiornare i valori PostgreSQL - Implementato come una funzione temporanea con la gestione eccezione: INSERT un'eccezione quando UPDATE unique_constraint
SQLite - Implementato come due query INSERT; AGGIORNARE. Ciò significa che l'aggiornamento viene eseguito indipendentemente dal fatto che la fila già esisteva o no

+0

Usa upsert, ma se ha eseguito un inserimento, dovrai quindi ottenere l'oggetto inserito :(- http://stackoverflow.com/a/29071422/48348 –

0

Ecco un semplice esempio che o aggiornamenti deviceID -> pushToken mappatura o lo crea:

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

mi piaceva l'idea di Ataik, ma ha reso un po 'più corto:

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

Usage:

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

Opzionale: aggiungere la manipolazione qui l'errore, ma vi consiglio vivamente di catena tutti promette una richiesta e alla fine ha un gestore errori.

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