sql >> Base de Datos >  >> NoSQL >> MongoDB

MongoDB:inserte si no existe, de lo contrario, omita

Tienes dos opciones reales aquí dependiendo de cómo quieras manejar las cosas:

  1. Use upsert funcionalidad de MongoDB para esencialmente "buscar" si existen los datos clave. De lo contrario, solo pasa los datos a $setOnInsert y eso no tocará nada más.

  2. Utilice operaciones "No ordenadas" a granel. Todo el lote de actualizaciones continuará incluso si se devuelve un error, pero los informes de error son solo eso, y todo lo que no sea un error se cometerá.

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

Tenga en cuenta que la "acción modificada" en los controladores actuales es que la respuesta del resultado en .execute() voluntad devolver un objeto de error para ser lanzado, donde versiones anteriores no lo hicieron con operaciones "No ordenadas".

Esto hace que sea imperativo que su código nunca se base en err devuelto solo, y deberías estar procesando el result devuelto en cambio, para la clasificación completa de errores.

No obstante, cuando no se ordena, el lote continúa hasta el final, sin importar cuántos errores ocurran. Las cosas que no sean un error se cometerán con normalidad.

Esto realmente se reduce a "es importante la secuencia". Si es así, entonces necesita operaciones "Ordenadas" y solo puede evitar claves duplicadas usando "upserts". De lo contrario, use "desordenado", pero tenga en cuenta los errores que se devuelven y lo que realmente significan.

Además, al usar .collection para obtener el objeto de colección subyacente del controlador base para habilitar las operaciones "en masa", asegúrese siempre de que se haya llamado primero a "algún" método de mangosta.

Sin eso, no hay una conexión garantizada a la base de datos con los métodos del controlador nativo como se maneja para los métodos mongoose, por lo que la operación fallará debido a que no hay conexión.

La alternativa a "activar" primero un método mangosta es envolver la lógica de su aplicación en un detector de eventos para la conexión:

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