Проблема, с которой вы столкнулись, связана с тем, что вы не создали индекс sparse
или partial
для поля username
.
Не делайте этого
// Mongoose Schema Version
const UserSchema = new mongoose.Schema({
email: {
type: String,
required: true,
unique: true,
trim: true
},
username: {
type: String,
required: false,
unique: true,
trim: true
}
})
// Mongo Version
db.users.createIndex({ email: 1 }, { unique: true });
db.users.createIndex({ username: 1}, { unique: true });
// Mongoose Verion (Users is a Schema)
UserSchema.index({ email: 1 }, { unique: true });
UserSchema.index({ username: 1 }, { unique: true });
У вас возникнет следующая проблема:
- ВСТАВИТЬ
{email: 'me@email.com'}
- Попытка ВСТАВИТЬ
{email: 'you@email.com'}
- ОШИБКА!
В MongoDB у вас есть две записи, которые пытаются установить username
на null
. Независимо от того, устанавливают ли они явно или неявно (пропуская username
), этот индекс не сможет хранить два элемента null
при их столкновении. Вот почему, если вы установите индивидуальные индексы для полей, БД будет зависать до тех пор, пока пользователь не завершит первый шаг, что позволяет другому пользователю перейти на первый шаг и ввести null
имя пользователя, но снова блокирует БД , Это можно решить с помощью составного индекса, однако это вызовет другие проблемы, такие как пользователи, регистрирующие одно и то же электронное письмо на два имени пользователя.
Сделайте это для MongoDB новее, чем 3.2
Частичные индексы индексируют только те документы в коллекции, которые соответствуют указанному выражению фильтра. Индексируя подмножество документов в собрании, частичные индексы снижают требования к хранилищу и снижают затраты производительности для создания и обслуживания индекса.
// Mongo Version
db.users.createIndex({ email: 1 }, { unique: true });
db.users.createIndex({ username: 1}, { unique: true, partialFilterExpression: { username: { $exists: true } } });
// Mongoose Verion (Users is a Schema)
UserSchema.index({ email: 1 }, { unique: true });
UserSchema.index({ username: 1 }, { unique: true, partialFilterExpression: { username: { $exists: true } } });
Сделайте это для MongoDB старше 3,2
Разреженные индексы содержат записи только для документов, имеющих индексированное поле, даже если поле индекса содержит нулевое значение. Индекс пропускает любой документ, в котором отсутствует индексированное поле. Индекс является «разреженным», поскольку он не включает в себя все документы коллекции. Напротив, не разреженные индексы содержат все документы в коллекции, храня нулевые значения для тех документов, которые не содержат индексированное поле.
// Mongoose Schema Version
const UserSchema = new mongoose.Schema({
email: {
type: String,
required: true,
unique: true,
trim: true
},
username: {
type: String,
required: false,
unique: true,
sparse: true,
trim: true
}
})
// Mongo Version
db.users.createIndex({ email: 1 }, { unique: true });
db.users.createIndex({ username: 1}, { unique: true, sparse: true });
// Mongoose Verion (Users is a Schema)
UserSchema.index({ email: 1 }, { unique: true });
UserSchema.index({ username: 1 }, { unique: true, sparse: true });
Изменено в версии 3.2: Начиная с MongoDB 3.2, MongoDB предоставляет возможность создавать частичные индексы. Частичные индексы предлагают расширенный набор функциональных возможностей разреженных индексов. Если вы используете MongoDB 3.2 или более позднюю версию, частичные индексы следует отдавать предпочтение перед разреженными.