MongoDB
 sql >> Base de données >  >> NoSQL >> MongoDB

MongoDB - Insérez s'il n'existe pas, sinon ignorez

Vous avez deux vrais choix ici selon la façon dont vous voulez gérer les choses :

  1. Utilisez upsert fonctionnalité de MongoDB pour "rechercher" essentiellement si les données clés existent. Sinon, vous transmettez uniquement les données à $setOnInsert et cela ne touchera à rien d'autre.

  2. Utilisez les opérations "UnOrdered" en vrac. L'ensemble du lot de mises à jour continuera même si une erreur est renvoyée, mais le ou les rapports d'erreur ne sont que cela, et tout ce qui n'est pas une erreur sera commis.

Exemple complet :

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

Notez que "l'action modifiée" dans les pilotes actuels est que la réponse de résultat sur .execute() va renvoie un objet d'erreur à lancer, là où les versions précédentes ne le faisaient pas avec les opérations "non ordonnées".

Il est donc impératif que votre code ne repose jamais sur le err renvoyé seul, et vous devriez consulter le result renvoyé à la place pour la classification complète des erreurs.

Néanmoins, lorsqu'il n'est pas ordonné, le lot continue jusqu'à la fin, quel que soit le nombre d'erreurs qui se produisent. Les choses qui ne sont pas une erreur seront validées normalement.

Cela revient vraiment à "la séquence est-elle importante". Si tel est le cas, vous avez besoin d'opérations "ordonnées" et vous ne pouvez éviter les clés en double qu'en utilisant des "upserts". Sinon, utilisez "non ordonné", mais soyez conscient des retours d'erreur et de ce qu'ils signifient réellement.

Aussi, lors de l'utilisation de .collection pour obtenir l'objet de collection sous-jacent du pilote de base afin d'activer les opérations "Bulk", assurez-vous toujours que l'une ou l'autre des méthodes "mongoose" a toujours été appelée en premier.

Sans cela, il n'y a pas de connexion garantie à la base de données avec les méthodes de pilote natives car elle est gérée pour les méthodes de mangouste, donc l'opération échouera en raison de l'absence de connexion.

L'alternative au "lancement" d'abord d'une méthode mangouste consiste à encapsuler la logique de votre application dans un écouteur d'événement pour la connexion :

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