MongoDB
 sql >> Datenbank >  >> NoSQL >> MongoDB

MongoDB- Einfügen, falls nicht vorhanden, ansonsten überspringen

Sie haben hier zwei wirkliche Möglichkeiten, je nachdem, wie Sie die Dinge handhaben möchten:

  1. Verwenden Sie upsert Funktionalität von MongoDB, um im Wesentlichen nachzuschlagen, ob die Schlüsseldaten vorhanden sind. Wenn nicht, geben Sie die Daten nur an $setOnInsert und das wird nichts anderes berühren.

  2. Verwenden Sie "Ungeordnete" Operationen in Bulk. Der gesamte Update-Stapel wird auch dann fortgesetzt, wenn ein Fehler zurückgegeben wird, aber die Fehlerberichte sind genau das, und alles, was kein Fehler ist, wird übernommen.

Ganzes Beispiel:

var async = require('async'),
    mongoose = require('mongoose'),
    Schema = mongoose.Schema;

var testSchema = new Schema({
  "_id": Number,
  "name": String
},{ "_id": false });

var Test = mongoose.model('Test',testSchema,'test');

mongoose.connect('mongodb://localhost/test');

var data = [
  { "_id": 1, "name": "One" },
  { "_id": 1, "name": "Another" },
  { "_id": 2, "name": "Two" }
];

async.series(
  [
    // Start fresh
    function(callback) {
      Test.remove({},callback);
    },

    // Ordered will fail on error. Upserts never fail!
    function(callback) {
      var bulk = Test.collection.initializeOrderedBulkOp();
      data.forEach(function(item) {
        bulk.find({ "_id": item._id }).upsert().updateOne({
          "$setOnInsert": { "name": item.name }
        });
      });
      bulk.execute(callback);
    },

    // All as expected
    function(callback) {
      Test.find().exec(function(err,docs) {
        console.log(docs)
        callback(err);
      });
    },


    // Start again
    function(callback) {
      Test.remove({},callback);
    },

    // Unordered will just continue on error and record an error
    function(callback) {
      var bulk = Test.collection.initializeUnorderedBulkOp();
      data.forEach(function(item) {
        bulk.insert(item);
      });
      bulk.execute(function(err,result) {
        callback(); // so what! Could not care about errors
      });
    },


    // Still processed the whole batch
    function(callback) {
      Test.find().exec(function(err,docs) {
        console.log(docs)
        callback(err);
      });
    }
  ],
  function(err) {
    if (err) throw err;
    mongoose.disconnect();
  }
);

Beachten Sie, dass die „geänderte Aktion“ in aktuellen Treibern darin besteht, dass das Ergebnis auf .execute() antwortet wird gibt ein zu werfendes Fehlerobjekt zurück, wo frühere Releases dies bei "ungeordneten" Operationen nicht getan haben.

Daher ist es unerlässlich, dass Ihr Code niemals auf err angewiesen ist allein zurückgegeben, und Sie sollten das zurückgegebene result eingeben stattdessen für die vollständige Klassifizierung von Fehlern.

Nichtsdestotrotz läuft der Batch im ungeordneten Zustand bis zum Ende weiter, egal wie viele Fehler auftreten. Dinge, die kein Fehler sind, werden ganz normal übergeben.

Dies läuft wirklich darauf hinaus, "ist die Reihenfolge wichtig". Wenn ja, dann benötigen Sie "Ordered"-Operationen und können doppelte Schlüssel nur durch "Upserts" vermeiden. Verwenden Sie andernfalls "unordered", aber beachten Sie die Fehlermeldungen und was sie tatsächlich bedeuten.

Auch bei Verwendung von .collection Um das zugrunde liegende Sammlungsobjekt vom Basistreiber zu erhalten, um "Massen"-Operationen zu ermöglichen, stellen Sie immer sicher, dass eine "irgendeine" Mungo-Methode immer zuerst aufgerufen wurde.

Ohne dies gibt es mit den Methoden des nativen Treibers keine garantierte Verbindung zur Datenbank, wie es für die Mongoose-Methoden gehandhabt wird, sodass der Vorgang aufgrund fehlender Verbindung fehlschlägt.

Die Alternative zum „Abfeuern“ einer Mungo-Methode besteht darin, Ihre App-Logik in einen Ereignis-Listener für die Verbindung einzuschließen:

mongoose.connection.on("open",function(err) {
    // app logic in here
})