【问题标题】:MongoDB Node.js native driver silently swallows `bulkWrite` exceptionMongoDB Node.js 原生驱动默默吞下 `bulkWrite` 异常
【发布时间】:2017-10-12 11:29:55
【问题描述】:

下面的脚本在 mongo bulkWrite op 语法中有一个错误:$setOnInsert: { count:0 }, 是不必要的,因此 mongo 会抛出异常:“无法同时更新 'count' 和 'count'”。

问题是,node.js 驱动程序似乎没有捕捉到它。此脚本记录“成功!”到控制台。

(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 {
    await db.collection("myNewCollection").bulkWrite(mongoOps);
    console.log("Success!");
  } catch(e) {
    console.log("Failed:");
    console.log(e);
  }

})();

db.setProfileLevel(2)检查db.system.profile.find({})我们可以看到异常:

{
    "op" : "update",
    "ns" : "myNewDb.myNewCollection",
    "query" : {
        "foo" : "bar"
    },
    "updateobj" : {
        "$setOnInsert" : {
            "count" : 0
        },
        "$inc" : {
            "count" : 1
        }
    },
    "keyUpdates" : 0,
    "writeConflicts" : 0,
    "numYield" : 0,
    "locks" : {
        "Global" : {
            "acquireCount" : {
                "r" : NumberLong(1),
                "w" : NumberLong(1)
            }
        },
        "Database" : {
            "acquireCount" : {
                "w" : NumberLong(1)
            }
        },
        "Collection" : {
            "acquireCount" : {
                "w" : NumberLong(1)
            }
        }
    },
    "exception" : "Cannot update 'count' and 'count' at the same time",
    "exceptionCode" : 16836,
    "millis" : 0,
    "execStats" : {},
    "ts" : ISODate("2017-10-12T01:57:03.008Z"),
    "client" : "127.0.0.1",
    "allUsers" : [],
    "user" : ""
}

为什么驱动程序会吞下这样的错误?我确实看起来像一个错误,但我想我会先在这里问一下以确保。

【问题讨论】:

  • 有趣。该错误实际上存在于响应中,但没有引发异常。尽管存在writeErrors,但响应状态也是ok: 1,这至少给出了在源中查找位置的指示。但这绝对是一个错误。因此,您可以通过检查响应中writeErrors 的长度来“解决”问题。但你真的不应该这样做。

标签: node.js mongodb


【解决方案1】:

正如评论所说,“这是一个错误”。具体的错误是right here

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

问题在于,被包裹在Promise 中的回调中的“响应”(或r)实际上并不是null,因此尽管存在错误,因此条件不是@987654327 @ 和 reject(err) 没有被调用,而是 resolve(r) 被发送,因此这不被视为异常。

更正需要进行一些分类,但您可以通过检查当前bulkWrite() 实现的响应中的writeErrors 属性来“解决”问题,或者考虑其他替代方案之一:

直接使用 Bulk API 方法:

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

})();

完全没问题,但当然存在一个问题,即在没有 Bulk API 支持的情况下,服务器实现不会自然地回归到使用旧版 API 方法。

手动包装 Promise

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

})();

如前所述,问题在于bulkWrite() 如何以Promise 返回的实现。因此,您可以使用callback() 表单进行编码,并进行自己的Promise 包装,以便按照您的预期行事。

再次如前所述,需要一个 JIRA 问题和分类,这是处理异常的正确方法。但希望很快得到解决。同时,从上面选择一种方法。

【讨论】:

  • 谢谢,尼尔!是的,我目前正在通过检查结果对象来解决问题。我假设您是维护者,或者您正在报告此问题,因为这似乎出现在您的回答中,但是如果您希望我在某处发布错误报告,请告诉我,我会直接跳到它。
  • @JoeRocc 其实已经发布了。NODE-1158 已添加用于跟踪。
  • 从 3.0.0 开始修复
猜你喜欢
  • 1970-01-01
  • 2021-02-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-05-09
相关资源
最近更新 更多