Reputation:
I have a userSchema
like so:
var userSchema = new Schema({
name: {
type: String
, required: true
, validate: [validators.notEmpty, 'Name is empty']
}
, username: {
type: String
, required: true
, unique: true
, validate: [validators.notEmpty, 'Username is empty']
}
});
The username
field is supposed to be unique. Mongoose will throw an error if this username already exists in the database. However, it is not case insensitive, which I need it to be.
Am I right in thinking that the only way to achieve a case insensitive unique check is to write my own validation rule, which will perform a query on the collection? Is it OK to write validation checks like this, creating more connections to the collection? I will need to do something similar for email
, too.
Upvotes: 20
Views: 32643
Reputation: 419
... with mongoose on NodeJS that query:
const countryName = req.params.country;
{ 'country': new RegExp(`^${countryName}$`, 'i') };
or
const countryName = req.params.country;
{ 'country': { $regex: new RegExp(`^${countryName}$`), $options: 'i' } };
// ^australia$
or
const countryName = req.params.country;
{ 'country': { $regex: new RegExp(`^${countryName}$`, 'i') } };
// ^turkey$
A full code example in Javascript, NodeJS with Mongoose ORM on MongoDB
// get all customers that given country name
app.get('/customers/country/:countryName', (req, res) => {
//res.send(`Got a GET request at /customer/country/${req.params.countryName}`);
const countryName = req.params.countryName;
// using Regular Expression (case intensitive and equal): ^australia$
// const query = { 'country': new RegExp(`^${countryName}$`, 'i') };
// const query = { 'country': { $regex: new RegExp(`^${countryName}$`, 'i') } };
const query = { 'country': { $regex: new RegExp(`^${countryName}$`), $options: 'i' } };
Customer.find(query).sort({ name: 'asc' })
.then(customers => {
res.json(customers);
})
.catch(error => {
// error..
res.send(error.message);
});
});
Upvotes: 7
Reputation: 36
I had the same issue while working on a project.I simply make it simple with two lines of code. converting all incoming value to small letters .
let getUsername = req.body.username;
let username = getUsername.toLowerCase();
Upvotes: 0
Reputation: 4778
A collation with strength: 2
on the index solves this issue.
index: {
unique: true,
collation: {
locale: 'en',
strength: 2
}
}
Place this in your Schema creation code as follows:
var userSchema = new Schema({
...
username: {
type: String,
required: true,
index: {
unique: true,
collation: { locale: 'en', strength: 2 }
}
});
Note: make sure the index on the model gets updated - you might need to do this manually.
Upvotes: 14
Reputation: 6245
I use mongoose-unique-validator
Example :
const mongoose = require('mongoose');
const uniqueValidator = require('mongoose-unique-validator');
const { Schema } = mongoose;
const UserSchema = new Schema({
name: {
type: String,
required: true,
unique: true,
index: true,
maxlength: 100,
trim: true,
uniqueCaseInsensitive: true
},
username: {
type: String,
required: true,
unique: true,
index: true,
maxlength: 100,
trim: true,
uniqueCaseInsensitive: true
}
});
UserSchema.plugin(uniqueValidator, {
message: 'Error, expected {PATH} to be unique.'
});
module.exports = mongoose.model('User', UserSchema);
Upvotes: 1
Reputation: 1006
The best way is to use already existing npm packages as shared below. https://www.npmjs.com/package/mongoose-unique-validator
To make it case sensitive you can follow uniqueCaseInsensitive in the same page.
No need to write your own validation logic when there is already a package available for this(follow Avinash's post too).
Upvotes: 1
Reputation: 4167
Very simple solution
username : {
trim:true,
//lowercase:true,
type:String,
required:[true, '{PATH} is required.'],
match : [
new RegExp('^[a-z0-9_.-]+$', 'i'),
'{PATH} \'{VALUE}\' is not valid. Use only letters, numbers, underscore or dot.'
],
minlength:5,
maxlength:30,
//unique:true
validate : [
function(un, cb){
console.log(v);
student.findOne({username:/^un$/i}, function(err, doc){
if(err) return console.log(err);
if(!_.isEmpty(doc)) return cb(false);
return cb(true);
});
},
'Username already exists.'
]
},
Here, I am using async validation and checking in my model student
if same field exist. Use can obviously use regex if you want.
But I would not recommend this method, it just doesn't fit in my head.
Instead stick with { type: String, lowercase: true, trim: true, unique:true }
approach and copy the original username to some other field in case you need it.
Upvotes: 0
Reputation: 419
I don't know if you are doing this in node. But you can use a npm like this: https://github.com/blakehaswell/mongoose-unique-validator to check unique validation on the fields of collections. Other way could be checking in the collection every time a new requests come. http://timstermatic.github.io/blog/2013/08/06/async-unique-validation-with-expressjs-and-mongoose/ You can refer the material here and use it the way suitable for your case.
Upvotes: 2
Reputation: 504
How about using a regular expression?
var pattern = [ /some pattern/, "{VALUE} is not a valid user name!" ];
{ type: String, match: pattern }
For further reference: http://mongoosejs.com/docs/api.html#schematype_SchemaType-required
Upvotes: -2
Reputation: 5534
What about using:
{ type: String, lowercase: true, trim: true }
to achieve your purpose?
Upvotes: 20