MongoDB
 sql >> Base de Dados >  >> NoSQL >> MongoDB

MongoDB- Insira se não existir, senão pule


Você tem duas opções reais aqui, dependendo de como deseja lidar com as coisas:

  1. Use upsert funcionalidade do MongoDB para essencialmente "pesquisar" se os dados principais existirem. Caso contrário, você só passa os dados para $setOnInsert e isso não tocará em mais nada.

  2. Use operações "UnOrdered" em massa. Todo o lote de atualizações continuará mesmo se um erro for retornado, mas os relatórios de erro são apenas isso, e qualquer coisa que não seja um erro será confirmada.

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

Observe que a "ação alterada" nos drivers atuais é que a resposta do resultado em .execute() vai retornar um objeto de erro a ser lançado, onde as versões anteriores não o faziam com operações "Un-ordered".

Isso torna imperativo que seu código nunca dependa do err retornado sozinho, e você deve estar inspetando o result retornado em vez disso, para a classificação completa dos erros.

No entanto, quando não ordenado, o lote continua até o final, não importa quantos erros ocorram. Coisas que não são um erro serão cometidas normalmente.

Isso realmente se resume a "sequência importante". Nesse caso, você precisa de operações "Ordenadas" e só pode evitar chaves duplicadas usando "upserts". Caso contrário, use "unordered", mas esteja ciente dos retornos de erro e o que eles realmente significam.

Além disso, ao usar .collection para obter o objeto de coleção subjacente do driver base para habilitar operações "em massa", sempre certifique-se de que o método "some" do mangusto sempre foi chamado primeiro.

Sem isso, não há conexão garantida ao banco de dados com os métodos do driver nativo, pois ele é tratado pelos métodos do mangusto, portanto, a operação falhará devido à falta de conexão.

A alternativa para "disparar" um método mangusto primeiro é envolver a lógica do seu aplicativo em um ouvinte de eventos para a conexão:
mongoose.connection.on("open",function(err) {
    // app logic in here
})