0

In my user document, I want to individually index email and username as unique fields, so that a duplicate is never entered.

The problem is all of the documentation I have found for multiple unique indexes is for "Compound Indexing", which appears to somehow tie the second index to the first. I don't want that.

All I want is for in my signup step 1 if a user submits an email that already exists for MongoDB to return an error that it already exists, and exact same for step 2, when they set their username.

So I want them indexed and unique separate from each other. I'm using this now and it is tieing the 2 together somehow which is not what I want:

const UserSchema = new mongoose.Schema({
  email: {
    type: String,
    required: true,
    trim: true
  },
  username: {
    type: String,
    required: false,
    trim: true
  }
})

UserSchema.index({
  email: 1,
  username: 1
}, {
  unique: true
});
user7637745
  • 965
  • 2
  • 14
  • 27
PurplePanda
  • 629
  • 9
  • 29

2 Answers2

1

Mongoose doesn't have a built-in validation for unique fields. I recommend the package (with this you can use the unique validator on the email and username fields): mongoose-unique-validator. Extend your code with:

let uniqueValidator = require('mongoose-unique-validator');

email: {
  type: String,
  required: true,
  trim: true,
  unique: true,
  index: true
},
  username: {
  type: String,
  required: false,
  trim: true,
  unique: true,
  index: true
}

UserSchema.plugin(uniqueValidator, {message: 'is already taken.'});
  • So I have actually basically already implemented this mysef. Before any username or email is ever saved I "find" that email or username and if nothing comes up I allow it to continue. This works well except for the edge case where 2 of the same emails are saved at the exact same time and because my checks are async they could both be saved. This problem still exists with your package's solution. All I need is a way to have mongo uniquely index these 2 fields independently of each other so that mongo will never save if it already exists thus fixing my edge case. – PurplePanda Jul 05 '18 at 03:22
0

Add unique: true to each field's definition in the schema to create separate, unique indexes for those fields:

const UserSchema = new mongoose.Schema({
  email: {
    type: String,
    required: true,
    trim: true,
    unique: true
  },
    username: {
    type: String,
    required: false,
    trim: true,
    unique: true
  }
})

See the Indexes section on this page for the documentation.

JohnnyHK
  • 305,182
  • 66
  • 621
  • 471
  • For whatever reason, this doesn't work. Somehow the first field is being associated with the second. I tried this and when I have a user in the signup process who has set an email but not set their username yet. Any other user who tries to sign up and save their email will get the mongo error that their email is not unique. What you have done is compound indexing. I need individual indexing. – PurplePanda Jul 05 '18 at 03:19
  • 1
    They're individual indexes, but if `username` can be missing, you also need to make that index "sparse". Add `sparse: true` to the field definition to allow multiple "nulls". Note that you'll manually need to drop that index first as mongoose won't replace the existing index. – JohnnyHK Jul 05 '18 at 03:35
  • See [here](https://stackoverflow.com/questions/7955040/mongodb-mongoose-unique-if-not-null) for a similar question. – JohnnyHK Jul 05 '18 at 04:35