MongoDB Node.js本地驱动程序默默吞下`bulkWrite`exception

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

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

 (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({}) ,我们可以看到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" : "" } 

为什么司机吞咽这样的错误? 我绝对看起来像一个错误,但我想我会问在这里,只是为了确保。

正如所评论的,“这是一个错误”。 具体来说,错误就在这里 :

  // 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中的callback中的“响应”(或者r )实际上并不为null ,因此尽pipe存在错误,条件也不是true并且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(); } })(); 

非常好,但是当然,如​​果没有批量API支持的话,服务器实现不会自然而然地退化,而是使用传统的API方法。

手工包装的承诺

 (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()forms进行编码,并执行自己的Promise包装,以便按照预期的方式进行操作。

同样如上所述,需要一个JIRA问题和Triage来处理exception。 但希望很快得到解决。 同时,从上面select一个方法。