how to recover from duplicate key in mongoose + express

11,115

Solution 1

I have not tried this yet, but this is what I'm thinking will avoid causing an error:

//look for existing user first
user.findOne({ username: req.body.username }, function(err, user) {
  if ( err ) throw err;

  //existing user found, stop registration
  if ( user ) {
      res.flash('error', "That user already exists");
      res.redirect('/signup');
      return;
  }

  //create new user
  var user = new User({ username: req.body.username });

  user.save(function(err){
   if ( err ) throw err;
      res.flash('info', "Your account has been created");
      res.redirect('/account');
  });
});

Solution 2

Try this:

user.save(function(err){
  if ( err && err.code !== 11000 ) {
    console.log(err);
    console.log(err.code);
    res.send('Another error showed up');
    return;
  }

  //duplicate key
  if ( err && err.code === 11000 ) {
    req.flash('error', 'User already exists');
    res.redirect('/signup');
    return;
  }

  res.locals.user = user;
  req.session.user = user;
  //res.locals.session = req.session;
  res.redirect('/');
});

You won't fill the error log this way.

Share:
11,115

Related videos on Youtube

chovy
Author by

chovy

Javascript Hacker who loves node + svelte.

Updated on September 14, 2022

Comments

  • chovy
    chovy over 1 year

    I've created a signup form using mongoose and express 3

    Its possible the user already exists with that username, in which case I get an err.code 11000 (duplicate key). How should I handle existing users?

    This is what I'm doing now....but I'm not sure checking error code is best way:

      user.save(function(err){
        if ( err ) {
          console.log(err);
          console.log(err.code);
    
          //duplicate key
          if ( err.code == 11000 ) {
            req.flash('error', 'User already exists');
            res.redirect('/signup');
            return;
          }
        }
    
        res.locals.user = user;
        req.session.user = user;
        //res.locals.session = req.session;
        res.redirect('/');
      });
    

    Is there a better way of doing this?

  • chovy
    chovy over 11 years
    isn't that what I had? What's hte difference. and errors do show up in log regardless...not sure how this is any different.
  • red
    red over 11 years
    Sorry @chovy, modified my answer a bit. - First conditional will happen in case the error is not a "duplicate key" error and return 'Another error showed up' to the client. - Second conditional will happen in case the error is a "duplicate key" error. - If no error, the script will go as instructed.
  • chovy
    chovy over 11 years
    I see -- thanks. I still think errors are logged though, since the query threw an error. I might do user.findOne(.., function(err, user) { if ( !user ) new User(); user.save() });
  • Matt Fletcher
    Matt Fletcher over 9 years
    You can also use .count() which is slightly more succinct/memorable but doesn't allow for using the returned data if required.
  • Matt Fletcher
    Matt Fletcher over 9 years
    Ps, I do think that mongoose should have something like Model.saveUnique({username: req.body.username}, function (err) { ... });
  • binki
    binki almost 7 years
    It is actually safer to handle the duplicate key error because it is possible for another request to have created the user between when user.findOne() reads the collection and user.save() executes. I.e., there’s a race condition where your API could throw a 5xx error. For a form where you’re expecting the user not to exist already, just trying to save it and then handling an anticipated DuplicateKey error is less code (no need for user.findOne()) and avoids this race condition. If you expect the entity to exist already, it might be more natural to try to load it first.