MongoDB Node.js本机驱动程序默默地吞下`bulkWrite`异常

时间:2017-10-12 02:29:05

标签: node.js mongodb

下面的脚本在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.system.profile.find({})审核db.setProfileLevel(2),我们可以看到异常:

{
    "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" : ""
}

为什么司机吞下这样的错误?我看起来肯定是一个错误,但我想我先问这里只是为了确定。

1 个答案:

答案 0 :(得分:2)

所以评论,"它是一个错误"。具体来说,错误是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);
    });
  });

问题在于"响应"包含在r中的回调中的(或Promise)实际上并不是null,因此尽管存在错误,但条件不是true和{ {1}}未被调用,而是reject(err)正在被发送,因此这不被视为例外。

纠正需要一些分类,但你可以“解决”问题。通过检查当前resolve(r)实现的响应中的writeErrors属性或者考虑其他替代方案之一来提及:

直接使用批量API方法:

bulkWrite()

非常好但当然还有一个问题,即如果没有Bulk API支持使用旧版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();
  }

})();

如上所述,问题在于(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()换行,以便按照您的预期行事。

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