Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to get index name on duplicate document 11000 error? #2129

Closed
niftylettuce opened this issue Jun 6, 2014 · 18 comments
Closed

How to get index name on duplicate document 11000 error? #2129

niftylettuce opened this issue Jun 6, 2014 · 18 comments
Labels
help This issue can likely be resolved in GitHub issues. No bug fixes, features, or docs necessary

Comments

@niftylettuce
Copy link
Contributor

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 the err object?

@vkarpov15
Copy link
Collaborator

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.

@niftylettuce
Copy link
Contributor Author

@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

@paambaati
Copy link

@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

@paambaati
Copy link

@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?

@vkarpov15 vkarpov15 added this to the 4.0.2 milestone Apr 9, 2015
@vkarpov15
Copy link
Collaborator

@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

@vkarpov15 vkarpov15 removed this from the 4.0.2 milestone Apr 10, 2015
@vkarpov15 vkarpov15 added the help This issue can likely be resolved in GitHub issues. No bug fixes, features, or docs necessary label Apr 10, 2015
@bookercodes
Copy link

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

@bookercodes
Copy link

I wrote a module to extract the duplicate field. I hope someone finds it useful ❤️!

@vkarpov15
Copy link
Collaborator

Good job @alexbooker! There's also another plugin for that, see #2284 and https://www.npmjs.com/package/mongoose-beautiful-unique-validation

@nebulou5
Copy link

nebulou5 commented Jul 3, 2016

@vkarpov15 Dude, thank you! No more ugly 11000 and 11001 checks!

@vkarpov15
Copy link
Collaborator

Thank @alexbooker and co, they wrote the plugins :)

@thomas-lee
Copy link

thomas-lee commented Jul 14, 2016

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>

@ghost
Copy link

ghost commented Jul 27, 2016

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' ]

@Fire7
Copy link

Fire7 commented Feb 17, 2017

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"

@aichholzer
Copy link

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

@nicky-lenaers
Copy link

@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!

@vkarpov15
Copy link
Collaborator

@nicky-lenaers try this plugin

@Maxtermax
Copy link

Maxtermax commented Feb 13, 2019

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

@arnav-zek
Copy link

you guys can just use err.message.indexOf( 'theFieldInQuestion_1' ) === -1

@Automattic Automattic locked as resolved and limited conversation to collaborators Oct 7, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
help This issue can likely be resolved in GitHub issues. No bug fixes, features, or docs necessary
Projects
None yet
Development

No branches or pull requests