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

Le pilote natif MongoDB Node.js avale silencieusement l'exception "bulkWrite"

Donc, comme commenté, "C'est un bug". Plus précisément, le bogue est ici :

 // Return a Promise
  return new this.s.promiseLibrary(function(resolve, reject) {
    bulkWrite(self, operations, options, function(err, r) {
      if(err && r == null) return reject(err);
      resolve(r);
    });
  });

Le problème est que la "réponse" ( ou r ) dans le rappel qui est enveloppé dans une Promise n'est pas réellement null , et donc malgré la présence de l'erreur, la condition n'est donc pas true et reject(err) n'est pas appelé, mais plutôt le resolve(r) est envoyé et cela n'est donc pas considéré comme une exception.

La correction nécessiterait un triage, mais vous pouvez soit "contourner" comme mentionné en inspectant les writeErrors propriété dans la réponse du bulkWrite() actuel mise en œuvre ou envisager l'une des autres alternatives comme :

Utilisation directe des méthodes de l'API Bulk :

const MongoClient = require('mongodb').MongoClient,
      uri  = 'mongodb://localhost:27017/myNewDb';

(async () => {

  let db;

  try {

    db = await MongoClient.connect(uri);

    let bulk = db.collection('myNewCollection').initializeOrderedBulkOp();

    bulk.find({ foo: 'bar' }).upsert().updateOne({
      $setOnInsert: { count: 0 },
      $inc: { count: 0 }
    });

    let result = await bulk.execute();
    console.log(JSON.stringify(result,undefined,2));

  } catch(e) {
    console.error(e);
  } finally {
    db.close();
  }

})();

Parfaitement bien, mais a bien sûr le problème de ne pas régresser naturellement sur les implémentations de serveur sans prise en charge de l'API de transfert vers l'utilisation des méthodes d'API héritées à la place.

Concevoir la promesse manuellement

(async () => {

  let db = await require('mongodb').MongoClient.connect('mongodb://localhost:27017/myNewDb');

  let mongoOps = [{
    updateOne: {
      filter: { foo: "bar" },
      update: {
        $setOnInsert: { count:0 },
        $inc: { count:1 },
      },
      upsert: true,
    }
  }];

  try {
    let result = await new Promise((resolve,reject) => {

      db.collection("myNewCollection").bulkWrite(mongoOps, (err,r) => {
        if (err) reject(err);
        resolve(r);
      });
    });
    console.log(JSON.stringify(result,undefined,2));
    console.log("Success!");
  } catch(e) {
    console.log("Failed:");
    console.log(e);
  }

})();

Comme indiqué, le problème réside dans l'implémentation de la façon dont bulkWrite() revient en tant que Promise . Donc, à la place, vous pouvez coder avec le callback() formulaire et faites votre propre Promise envelopper afin d'agir comme vous l'attendez.

Encore une fois, comme indiqué, il faut un problème JIRA et un triage qui est la bonne façon de gérer les exceptions. Mais j'espère qu'il sera bientôt résolu. En attendant, choisissez une approche d'en haut.