MongoDB Node.js本机驱动程序无声地吞没了"bulkWrite"异常 [英] MongoDB Node.js native driver silently swallows `bulkWrite` exception

查看:48
本文介绍了MongoDB Node.js本机驱动程序无声地吞没了"bulkWrite"异常的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

下面的脚本在mongo bulkWrite op语法中存在一个错误:$setOnInsert: { count:0 },是不必要的,因此mongo引发异常:无法同时更新'count'和'count'".

The script below has a bug in the mongo bulkWrite op syntax: $setOnInsert: { count:0 }, is unnecessary and thus mongo throws an exception: "Cannot update 'count' and 'count' at the same time".

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

The problem is, the node.js driver doesn't seem to catch it. This script logs "Success!" to the console.

(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({})可以看到以下异常:

Examining db.system.profile.find({}) with db.setProfileLevel(2) we can see the exception:

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

为什么驾驶员会吞下这样的错误?我肯定看起来像是个错误,但我想我想先在这里问一下.

Why is the driver swallowing errors like this? I definitely seems like a bug, but I figured I'd ask here first just to be sure.

推荐答案

如此评论,这是一个错误".具体来说,该错误是就在这里:

So as commented, "It's a bug". Specifically the bug is 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,因此尽管存在错误,但条件不是reject(err)不会被调用,而是会发送resolve(r),因此这不被视为例外.

The problem is that the "response" ( or r ) in the callback which is being wrapped in a Promise is not actually null, and therefore despite the error being present the condition is therefore not true and reject(err) is not being called, but rather the resolve(r) is being sent and hence this is not considered an exception.

需要进行一些分类,但是您可以通过检查当前bulkWrite()实现的响应中的writeErrors属性来变通",或考虑以下其他替代方法之一:

Correcting would need some triage, but you can either 'work around' as mentioned by inspecting the writeErrors property in the response from the current bulkWrite() implementation or consider one of the other alternatives as:

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方法.

Perfectly fine but of course has the issue of not naturally regressing on server implementations without Bulk API support to using the legacy API methods instead.

(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包装,以按照您的期望进行操作.

As noted the problem lies within the implementation of how bulkWrite() is returning as a Promise. So instead you can code with the callback() form and do your own Promise wrapping in order to act how you expect it to.

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

Again as noted, needs a JIRA issue and Triage to which is the correct way to handle the exceptions. But hopefully gets resolved soon. In the meantime, pick an approach from above.

这篇关于MongoDB Node.js本机驱动程序无声地吞没了"bulkWrite"异常的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆