Hello,
While doing ordered bulk inserts I noticed that an error on a individual document get lost into a
GenericDriverException.
I'd rather have a more structured
LastError. (because I need to recover from duplicate key errors)
The reason of the behavior is that in
reactivemongo.api.collections.GenericCollection.Mongo26WriteCommand#send we have:
case Some(wr) if (wr.inError || (wr.hasErrors && ordered)) => { Future.failed(WriteResult.lastError(wr). getOrElse[Exception](GenericDriverException( s"write failure: $wr" ))) }
and in reactivemongo.api.commands.WriteResult#lastError:
def lastError(result: WriteResult): Option[LastError] = result match {
case error @ LastError(_, _, _, _, _, _, _, _, _, _, _, _, _, _) => Some(error)
case _ if (result.ok) => None
case _ => Some(LastError(
false, // ok
result.errmsg,Eg, if mongo (tested with 3.2) fail to insert a document due to a duplicate key, it will return an response like:
{
ok: BSONInteger(1),
n: BSONInteger(0),
writeErrors: [
0: {
index: BSONInteger(0),
code: BSONInteger(11000),
errmsg: "E11000 duplicate key error collection: test.events index: _id_ dup key: { : { key: ObjectId('56c6dc1eff2e140920771ee5'), seq: 12 } }"
}
]
}Has we can see, the corresponding write result will be "
ok" despite
writeErrors being non-empty. Hence we fall in the getOrElse clause resulting in errors being mangled into a GenericDriverException.
I guess one way to improve the situation is to change the implementation of WriteResult#lastError into something more like
def lastError(result: WriteResult): Option[LastError] = result match {
case error @ LastError(_, _, _, _, _, _, _, _, _, _, _, _, _, _) => Some(error)
case _ if (result.inError || result.hasErrors) => Some(LastError(
false, // ok
result.errmsg,
...
case _ => None
WDYT?
Best regards,
Jb