I am trying to make my user model not care about case sensitivity in email
and username
fields. So if I try to create a user with email [email protected]
and another one with [email protected]
, the second time it is not allowed, since the email is not unique, despite the upper case and lowercases.
My user schema is the following:
const UserSchema = new mongoose.Schema({
email: {
type: String,
unique: true,
required: true,
validate: // validators here,
},
username: {
type: String,
unique: true,
required: true,
validate: // validators here,
},
// Some other fields not case insensitive
});
The users are created with mongoose create function:
user = await User.create(userData)
I have tried creating a collation and it works with the find
command directly on mongo shell.
db.users.createIndex({'email': 1}, {'collation': { 'locale': 'en', 'strength': 2}, 'name': 'testcollation'})
db.users.find({'email':'[email protected]'}).collation({'locale':'en', 'strength': 2})
But when I try to append the collation to the create call, I get an error message saying collation function does not exist.
user = await User.create(userData).collation({ "locale": "en", "strength": 2 });
Following this link, https://mongoosejs.com/docs/api.html#query_Query-collation, I would expect this to work:
User.create(...).collation is not a function
Any idea how to run the collation with the create function?
CodePudding user response:
you cannot use collation with create since it only works with a find
cursor
Specifies the collation for the cursor returned by the db.collection.find(). To use, append to the db.collection.find()
For your scenario you may want to use a pre save hook
e.g.
schema.pre("save", function(next) {
// ...do something with "this"
next();
});
CodePudding user response:
Mongoose validators can be a bit tricky because there are certain race conditions, particularly when using the 'unique' index which is not inherently a validation method. It only creates a unique index, which can take a beat to process. If two people try to sign up at the same time, there is a chance that the index would not build in time to recognize the duplicate key.
Personally, my preferred method is to read the database first, then depending on the response, process the new create or reject as a duplicate. In your case, I would use a simple regex to check the case insensitivity,
const checkUserDuplicate = await User.find({ email: `/${userData.email}/i` });
if (checkUserDuplicate && checkUserDuplicate.email === userData.email) {
return next(res.status(500).json('Email already in use'));
} else {
const user = await User.create(userData);
res.status(201).json(user);
}