看来MongoDBinsertMany()
将有序选项设置为 false 的函数可以比将有序选项设置为 true 更有效地插入文档。并且即使多个文档插入失败也可以继续插入文档。
但我发现没有干净的方法来获取每个失败文档的错误和总体命令结果。
(顺便说一句,我使用的是 Node.js 驱动程序 API 2.2。从现在开始我将参考驱动程序的源代码:http://mongodb.github.io/node-mongodb-native/2.2/api/lib_collection.js.html http://mongodb.github.io/node-mongodb-native/2.2/api/lib_collection.js.html)
首先,如果使用 Promise,则无法同时获取错误和结果。在源代码第 540 行,insertMany()
返回错误或结果 - 不是两者都返回,而bulkWrite()
回调在源代码第 703 行返回两者。
其次,如果使用回调,事情会变得更糟。什么时候bulkWrite()
调用带有错误和结果的回调,insertMany()
调用带有错误和结果的回调,但结果是 BulkWrite 的结果,而不是正确转换为 InsertManyResults 的结果。请查看源代码第535行。我认为这是一个错误。
甚至对于bulkWrite()
,当错误数为 1 时,它不会将结果正确转换为其格式。请看源代码第669行。我认为这也是一个bug。
现在我认为 Node.js 驱动程序根本没有准备好处理这种情况。
目前,似乎没有办法同时正确获取错误和结果。
我对吗?
UPDATE
我运行了一个基于 Neil Lunn 的答案的测试代码。自从我的
Node.js(4.4.5) 不理解 async/await,我不得不用显式 Promises 重写测试代码。
测试代码如下:
function doTest()
{
var MongoClient = require('mongodb').MongoClient;
var testData = [ 1,2,2,3,3,4,5,6,7,8,9 ];
var db;
return MongoClient.connect('mongodb://127.0.0.1/test')
.then(function (_db)
{
db = _db;
return db.createCollection('test');
})
.then(function ()
{
return db.collection('test').deleteMany({})
.then(function ()
{
return db.collection('test').insertMany(
testData.map(function (_id)
{
return { _id: _id };
}),
{ ordered: false })
.then(function (result)
{
console.log('Promise: result', result);
}, function (err)
{
console.log('Promise: error', err);
});
})
.then(function ()
{
return db.collection('test').deleteMany({});
})
.then(function ()
{
return new Promise(function (resolve, reject)
{
return db.collection('test').insertMany(
testData.map(function (_id)
{
return { _id: _id };
}),
{ ordered: false },
function (err, result)
{
console.log('callback: error', err);
console.log('callback: result', result);
console.log('callback: result.hasWriteErrors', result.hasWriteErrors());
console.log('callback: result.getWriteErrors',
JSON.stringify(result.getWriteErrors(), null, 2));
resolve();
});
});
});
})
.catch(function (err)
{
console.log('catch', err);
})
.then(function ()
{
db.close();
});
}
doTest();
这是结果:
Promise: error { [MongoError: write operation failed]
name: 'MongoError',
message: 'write operation failed',
driver: true,
code: 11000,
writeErrors:
[ { code: [Getter],
index: [Getter],
errmsg: [Getter],
getOperation: [Function],
toJSON: [Function],
toString: [Function] },
{ code: [Getter],
index: [Getter],
errmsg: [Getter],
getOperation: [Function],
toJSON: [Function],
toString: [Function] } ] }
callback: error { [MongoError: write operation failed]
name: 'MongoError',
message: 'write operation failed',
driver: true,
code: 11000,
writeErrors:
[ { code: [Getter],
index: [Getter],
errmsg: [Getter],
getOperation: [Function],
toJSON: [Function],
toString: [Function] },
{ code: [Getter],
index: [Getter],
errmsg: [Getter],
getOperation: [Function],
toJSON: [Function],
toString: [Function] } ] }
callback: result { ok: [Getter],
nInserted: [Getter],
nUpserted: [Getter],
nMatched: [Getter],
nModified: [Getter],
nRemoved: [Getter],
getInsertedIds: [Function],
getUpsertedIds: [Function],
getUpsertedIdAt: [Function],
getRawResponse: [Function],
hasWriteErrors: [Function],
getWriteErrorCount: [Function],
getWriteErrorAt: [Function],
getWriteErrors: [Function],
getLastOp: [Function],
getWriteConcernError: [Function],
toJSON: [Function],
toString: [Function],
isOk: [Function],
insertedCount: 9,
matchedCount: 0,
modifiedCount: 0,
deletedCount: 0,
upsertedCount: 0,
upsertedIds: {},
insertedIds:
{ '0': 1,
'1': 2,
'2': 2,
'3': 3,
'4': 3,
'5': 4,
'6': 5,
'7': 6,
'8': 7,
'9': 8,
'10': 9 },
n: 9 }
callback: result.hasWriteErrors true
callback: result.getWriteErrors [
{
"code": 11000,
"index": 2,
"errmsg": "E11000 duplicate key error collection: test.test index: _id_ dup key: { : 2 }",
"op": {
"_id": 2
}
},
{
"code": 11000,
"index": 4,
"errmsg": "E11000 duplicate key error collection: test.test index: _id_ dup key: { : 3 }",
"op": {
"_id": 3
}
}
]
现在,我再次运行代码,并将 testData 变量修改如下:
var testData = [ 1,2,3,3,4,5,6,7,8,9 ];
在这种情况下,错误数将为 1,而不是 2,因为重复的“2”已被删除。
这是结果:
Promise: error { [MongoError: E11000 duplicate key error collection: test.test index: _id_ dup key: { : 3 }]
name: 'MongoError',
message: 'E11000 duplicate key error collection: test.test index: _id_ dup key: { : 3 }',
driver: true,
code: 11000,
index: 3,
errmsg: 'E11000 duplicate key error collection: test.test index: _id_ dup key: { : 3 }',
getOperation: [Function],
toJSON: [Function],
toString: [Function] }
callback: error { [MongoError: E11000 duplicate key error collection: test.test index: _id_ dup key: { : 3 }]
name: 'MongoError',
message: 'E11000 duplicate key error collection: test.test index: _id_ dup key: { : 3 }',
driver: true,
code: 11000,
index: 3,
errmsg: 'E11000 duplicate key error collection: test.test index: _id_ dup key: { : 3 }',
getOperation: [Function],
toJSON: [Function],
toString: [Function] }
callback: result { ok: [Getter],
nInserted: [Getter],
nUpserted: [Getter],
nMatched: [Getter],
nModified: [Getter],
nRemoved: [Getter],
getInsertedIds: [Function],
getUpsertedIds: [Function],
getUpsertedIdAt: [Function],
getRawResponse: [Function],
hasWriteErrors: [Function],
getWriteErrorCount: [Function],
getWriteErrorAt: [Function],
getWriteErrors: [Function],
getLastOp: [Function],
getWriteConcernError: [Function],
toJSON: [Function],
toString: [Function],
isOk: [Function] }
callback: result.hasWriteErrors true
callback: result.getWriteErrors [
{
"code": 11000,
"index": 3,
"errmsg": "E11000 duplicate key error collection: test.test index: _id_ dup key: { : 3 }",
"op": {
"_id": 3
}
}
]
错误和结果的格式与第一次运行有很大不同。
- 该错误没有 writeErrors 字段。
- 结果没有“转换”字段。 (insertedCount、matchedCount 等)正如我上面所说,这是驱动程序源代码第 669 行上的一个“错误”。
在两次测试运行中,结果参数的类型都不是Collection~insertWriteOpResult
。第一个是Collection~bulkWriteOpCallback
,第二个是更内部的。因此,本例中的 API 文档是错误的。正如我上面所说,这是由第 535 行和 669 行上的“错误”引起的。
所以,即使结果可以使用(事实上,结果已经hasWriteErrors()
and getWriteErrors()
正如 Neil Lunn 所说),由于这种行为没有记录在案,我怀疑它可能会在以后的版本中更改,恕不另行通知,并且我的代码将会损坏。