MongoDB
 sql >> Database >  >> NoSQL >> MongoDB

MongoDB- Inserisci se non esiste, altrimenti salta

Hai due scelte reali qui a seconda di come vuoi gestire le cose:

  1. Usa upsert funzionalità di MongoDB per essenzialmente "cercare" se i dati chiave esistono. In caso contrario, trasferisci i dati solo a $setOnInsert e questo non toccherà nient'altro.

  2. Utilizza le operazioni "Non ordinate" in blocco. L'intero batch di aggiornamenti continuerà anche se viene restituito un errore, ma i rapporti di errore sono proprio questo e tutto ciò che non è un errore verrà commesso.

Esempio completo:

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

Nota che l'"azione modificata" nei driver attuali è la risposta del risultato su .execute() farà restituisce un oggetto di errore da generare, laddove le versioni precedenti non lo facevano con le operazioni "non ordinate".

Questo rende imperativo che il tuo codice non si basi mai su err restituito da solo e dovresti controllare il result restituito invece per la classificazione completa degli errori.

Tuttavia, se non ordinato, il batch continua fino alla fine, indipendentemente dal numero di errori che si verificano. Le cose che non sono un errore verranno commesse normalmente.

Questo si riduce davvero a "è importante la sequenza". Se è così, allora hai bisogno di operazioni "Ordinate" e puoi solo evitare chiavi duplicate usando "upsert". Altrimenti usa "non ordinato", ma tieni presente i ritorni di errore e cosa significano effettivamente.

Inoltre, quando si utilizza .collection per ottenere l'oggetto di raccolta sottostante dal driver di base per abilitare le operazioni "bulk", quindi assicurati sempre che uno dei metodi "qualche" mangusta sia sempre stato chiamato per primo.

Senza ciò, non esiste una connessione garantita al database con i metodi del driver nativo poiché viene gestita per i metodi mangusta, quindi l'operazione fallirà a causa dell'assenza di connessione.

L'alternativa all'"attivazione" prima di un metodo mangusta consiste nel racchiudere la logica dell'app in un listener di eventi per la connessione:

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