Closed niftylettuce closed 9 years ago
The best way right now is by parsing the error message (slightly hacky, yes). The error message looks like:
E11000 duplicate key error index: test.x.$a_1 dup key: { : 1.0 }
Looks pretty consistent across mongodb server 2.4 and 2.6. The index:
indicates which index causes the duplicate key error on the server side.
@vkarpov15 here's how I did it, in case anyone else wants to do this, or if you would like to add it to the wiki, documentation, or Readme perhaps -- it is rather useful for error handling.
// this example is showing how to get the field `email` out of the err message
var field = err.message.split('index: test.')[1].split('.$')[1]
// now we have `email_1 dup key`
field = field.split(' dup key')[0]
field = field.substring(0, field.lastIndexOf('_')) // returns email
I am using this directly in the error handler component of my new framework called Igloo.
https://github.com/niftylettuce/igloo
The commit with it:
https://github.com/niftylettuce/igloo/commit/3cdee8dcc28b6373a80a4e0c16c3f2c34edfca6c
@niftylettuce Can we not get it this way?
var field = err.message.split('.$')[1].split('_')[0];
This way, one does not have to know the database name.
EDIT on 31 January, 2015:
That breaks when the field name has an underscore in it. Use this instead.
var field = err.message.split('.$')[1];
// now we have `email_1 dup key`
field = field.split(' dup key')[0];
field = field.substring(0, field.lastIndexOf('_')); // returns email
@vkarpov15 After Mongoose 4.x, the error format seems to have changed a bit, and no longer contains the offending field name.
The error message, for example, on a field with unique:true
, sparse:true
and a null
value looks like this -
E11000 duplicate key error dup key: { : "<whatever_value_i_tried_to_insert>" }
Is there a way to get the field that is causing this error?
@paambaati that's not a mongoose issue, that string is generated by the mongodb server and is specific to the WiredTiger storage engine in mongodb 3.0.0 and 3.0.1. This bug was reported in the core server jira project, fixed, and the fix is in mongodb 3.0.2
Thanks to @paambaati I got the functionality I needed.
var user = new User(req.body);
user.save(function(error) {
if (error) {
if (error.code === 11000) {
// email or username could violate the unique index. we need to find out which field it was.
var field = error.message.split(".$")[1];
field = field.split(" dup key")[0];
field = field.substring(0, field.lastIndexOf("_"));
req.flash("errors", [{
msg: "An account with this " + field + " already exists."
}]);
res.redirect("/join");
return;
}
throw error;
}
req.flash("messages", "Thank you for joining.");
res.redirect("/");
});
But is there a terser way to get the same result? //cc @vkarpov15
I wrote a module to extract the duplicate field. I hope someone finds it useful :heart:!
Good job @alexbooker! There's also another plugin for that, see #2284 and https://www.npmjs.com/package/mongoose-beautiful-unique-validation
@vkarpov15 Dude, thank you! No more ugly 11000 and 11001 checks!
Thank @alexbooker and co, they wrote the plugins :)
Not sure if anyone still want to extract the value.
here is my code
const msg = 'E11000 duplicate key error dup key: { : "<whatever_value_i_tried_to_insert>" }';
msg.match(/dup key: { : "(.+)" }/)[1];
// <whatever_value_i_tried_to_insert>
And here i wrote mine to get both value and key This assumes fixed error msg format
const err.message = 'E11000 duplicate key error index: dev_app.users.$username_1 dup key: { : "debjyoti1" }'
let key_val = err.message.match(/index\:\ [a-z_]+\.[a-z_]+\.\$([a-z_]+)\_[0-9a-z]{1,}\s+dup key[: {]+"(.+)"/).splice(1,3);
// [ 'username', 'debjyoti1' ]
Here is my RegExp solution to get index name with any type of error syntax I have found:
var regex = /index\:\ (?:.*\.)?\$?(?:([_a-z0-9]*)(?:_\d*)|([_a-z0-9]*))\s*dup key/i,
match = error.message.match(regex),
indexName = match[1] || match[2];
Here what I have tested:
('E11000 duplicate key error collection: db.users index: name_1 dup key: { : "Kate" }').match(regex)[1]; // "name"
("E11000 duplicate key error index: myDb.myCollection.$id dup key: { : ObjectId('57226808ec55240c00000272') }").match(regex)[2] // "id"
('E11000 duplicate key error index: test.collection.$a.b_1 dup key: { : null }').match(regex)[1] // "b"
('E11000 duplicate key error collection: upsert_bug.col index: _id_ dup key: { : 3.0 }').match(regex)[1] // "_id"
My two cents:
let err = 'E11000 duplicate key error collection: home.users index: name_1 dup key: { : "francis" }';
let [i, field, value] = err.match(/index:\s([a-z]+).*{\s?\:\s?"([a-z]+)"/i);
console.log(field, value);
// name francis
MongoDB: v3.4.2
@Fire7 Thanks for your solution. I have, however, a compound unique index for say a name
and an owner
field on a project
model, such that there is never a project created with the same name by one owner.
Using your solution gives me name_1_owner
. Any idea how to solve this for compound unique indexes?
Thanks!
@nicky-lenaers try this plugin
Update 2019, for any one who wanna to use the plugin mongoose-beautiful-unique-validation be aware of this issue when use mongodb 3.6 to up
you guys can just use err.message.indexOf( 'theFieldInQuestion_1' ) === -1
How can I get the index for which the error occurs with?
e.g. if my index is named
email
, how do I get that from theerr
object?