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?
4
Answers
you cannot use collation with create since it only works with a
find
cursorFor your scenario you may want to use a pre save hook
e.g.
Personally, I prefer to query first, create or error if there’s a duplicate. In your case, I would use a simple regex to check the case insensitivity.
According to the docs this type of middleware should run after save.
You could then add
lowercase: true
to the user.email schema property which always calls.toLowerCase()
on the value.To run collation with create command in mongoose, you need to specify the collation option in the schema definition or in the create method. Collation is a feature that allows you to specify the rules for comparing strings in different languages and alphabets. For example, you can use collation to make your user model not care about case sensitivity in email and username fields.
Explanation
Mongoose is a popular object data modeling (ODM) library for MongoDB, a NoSQL database. Mongoose allows you to define schemas for your collections, which are like blueprints for your documents. Schemas can have various options, such as validators, indexes, hooks, virtuals, and collation.
Collation is an option that lets you define the language-specific rules for sorting and matching strings. For example, you can use collation to make your user model ignore the case of the email and username fields, so that [email protected] and [email protected] are considered the same. You can also use collation to sort strings according to different alphabets, such as Arabic, Cyrillic, or Latin.
To use collation in mongoose, you need to specify the collation option in the schema definition or in the create method. The collation option is an object that has several properties, such as locale, strength, caseLevel, and caseFirst. You can find the full list of collation properties and their meanings in the MongoDB documentation: https://docs.mongodb.com/manual/reference/collation/
For example, to make your user model not care about case sensitivity in email and username fields, you can use the following collation option:
You can then apply this collation option to your user schema or to your create method. For example:
Examples
Here are some examples of how collation works in mongoose:
If you create a user with email [email protected] and username Thisuser, and then try to create another user with email [email protected] and username thisuser, you will get a duplicate key error, because the collation option makes them equivalent.
If you create a user with email [email protected] and username Thisuser, and then try to find them by email [email protected] or username thisuser, you will get the same user, because the collation option makes them match.
If you create a user with email [email protected] and username Thisuser, and then try to sort them by email or username, you will get the same order regardless of the case, because the collation option makes them equal.
If you create a unique index on
email
with that collation, that should disallow creating duplicate emails at the database level:Creating this index should make your duplicate
User.create
calls fail. The Mongoose Schemaunique
option creates a similar index automatically, but it won’t be aware of your desired collation. I’m unsure whether there’s a way of setting up Mongoose schema settings to get it to create your desired index.You can also set the collation on the collection level in your
createCollection
call. You can’t modify an existing collection to have a different collation though: this will only work on initial collection creation.