wake-up-neo.com

Erstellen oder aktualisieren Sie Sequelize

Ich verwende Sequelize in meinem Nodejs-Projekt und habe ein Problem gefunden, das ich schwer zu lösen habe .. Im Grunde habe ich einen Cron, der ein Array von Objekten von einem Server erhält, als es in meiner Datenbank als Objekt (für diesen Fall Cartoons). Wenn ich aber bereits eines der Objekte habe, muss ich es aktualisieren.

Grundsätzlich habe ich ein Array von Objekten und könnte die BulkCreate () -Methode verwenden. Aber als der Cron neu startet, löst er das Problem nicht. Daher musste ich ein Update mit einem Up-True-Flag durchführen. Und das Hauptproblem: Ich muss einen Rückruf haben, der nur einmal ausgelöst wird, nachdem alle diese erstellt oder aktualisiert wurden. Hat jemand eine Idee, wie ich das machen kann? Durch ein Array von Objekten iterieren ... erstellen oder aktualisieren und danach einen einzelnen Rückruf erhalten?

Danke für ihre Aufmerksamkeit 

Von docs müssen Sie nicht where abfragen, um die Aktualisierung durchzuführen, sobald Sie das Objekt haben. Die Verwendung von Versprechen sollte auch Rückrufe vereinfachen:

Implementierung

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

Verwendungszweck

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

Hinweis

  1. diese Operation ist nicht atomar
  2. erstellt 2 Netzwerkanrufe

das heißt, es ist ratsam, den Ansatz zu überdenken und wahrscheinlich nur die Werte in einem Netzwerkaufruf zu aktualisieren. Entweder:

  1. schauen Sie sich den zurückgegebenen Wert an (d. h. Zeilen_beeinflusst) und entscheiden Sie, was zu tun ist
  2. gibt einen Erfolg zurück, wenn der Aktualisierungsvorgang erfolgreich ist. Dies liegt daran, dass die Verfügbarkeit dieser Ressource nicht in der Verantwortung dieses Dienstes liegt.
34
tsuz

Die Idee von Ataik hat mir gefallen, aber etwas kürzer:

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

Verwendungszweck:

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

Optional: Fügen Sie hier die Fehlerbehandlung hinzu. Es wird jedoch dringend empfohlen, alle Versprechen einer Anforderung zu verketten und am Ende einen Fehlerbehandler zu verwenden.

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

Sie können upsert .__ verwenden. Es ist viel einfacher.

Implementierungsdetails:

MySQL - Wird als einzelne Abfrage implementiert. INSERT-Werte ON DUPLICATE KEY
UPDATE-Werte PostgreSQL - Implementiert als temporäre Funktion mit Ausnahmebehandlung: INSERT EXCEPTION WHEN unique_constraint UPDATE
SQLite - Implementiert als zwei Abfragen INSERT; AKTUALISIEREN. Das bedeutet, dass Die Aktualisierung wird unabhängig davon ausgeführt, ob die Zeile bereits vorhanden war oder nicht

8
Alvaro Joao

Dies könnte eine alte Frage sein, aber ich habe es getan:

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);
8
Ateik

Sie möchten, dass Sie Ihre Sequelize-Anrufe in einem async.each einschließen.

2
dankohn

Dies kann mit dem benutzerdefinierten Ereignisemitter erfolgen. 

Angenommen, Ihre Daten befinden sich in einer Variablen namens Daten.

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
1
Jeff Ryan

Hier ein einfaches Beispiel, das entweder die deviceID -> pushToken-Zuordnung aktualisiert oder erstellt: 

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

sie können in sequelize die Methoden findOrCreate und dann update verwenden. Hier ist ein Beispiel mit 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
     });
});
0
User.upsert({ a: 'a', b: 'b', username: 'john' })

Es wird versucht, einen Datensatz nach Hash in 1. Parameter zu finden, um ihn zu aktualisieren. Wird er nicht gefunden, wird ein neuer Datensatz erstellt

Hier ist ein Beispiel für die Verwendung in Folgetests

it('works with upsert on id', function() {
    return this.User.upsert({ id: 42, username: 'john' }).then(created => {
        if (dialect === 'sqlite') {
            expect(created).to.be.undefined;
        } else {
            expect(created).to.be.ok;
        }

        this.clock.tick(1000);
        return this.User.upsert({ id: 42, username: 'doe' });
    }).then(created => {
        if (dialect === 'sqlite') {
            expect(created).to.be.undefined;
        } else {
            expect(created).not.to.be.ok;
        }

        return this.User.findByPk(42);
    }).then(user => {
        expect(user.createdAt).to.be.ok;
        expect(user.username).to.equal('doe');
        expect(user.updatedAt).to.be.afterTime(user.createdAt);
    });
});

0