Как создать несколько уникальных точек данных в схеме Mongoose? - PullRequest
0 голосов
/ 02 июля 2018

Я использую экспресс и с mongoose / mongo db и имею документ пользователя с 2 точками данных, которые я хочу быть уникальными (электронная почта и имя пользователя). Моя проблема в том, что мой процесс регистрации состоит из нескольких этапов, поэтому электронная почта сначала сохраняется, а затем на следующем этапе сохраняется имя пользователя. У меня есть ошибка, когда, если пользователь находится между шагами 1 и 2, другие пользователи не могут зарегистрироваться, потому что я получаю сообщение об ошибке, в котором говорится, что имя пользователя или электронная почта, которые они пытаются сохранить, не уникальны. Если пользователь, который был между шагами 1 и 2, закончил, тогда другой пользователь может создать электронное письмо, и оно отлично работает В настоящее время я занимаюсь составной индексацией и каким-то образом связывает 2 поля. Мне нужно решение, в котором mongo db возвращает ошибку, если пытается сохранить поле, но в этом поле уже существует идентичный фрагмент данных для другого пользователя. Я уже делаю свою собственную проверку, чтобы убедиться, что она уникальна, выполнив поиск по этому адресу электронной почты и разрешив сохранение, если поиск ничего не дал. Проблема в том, что он асинхронный, и пользователь может отправить одно и то же электронное письмо или имя пользователя дважды в одно и то же время, и он будет создан. Я хочу использовать уникальные индексы Монго для обоих полей по отдельности (никак не связанные), чтобы Монго возвратил ошибку, если не уникальную, таким образом решая этот крайний случай. Что я здесь не так делаю? Как сделать эти поля уникальными, но никак не связанными друг с другом? Вот суть моего кода:

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});

Ответы [ 2 ]

0 голосов
/ 11 июля 2018

Проблема, с которой вы столкнулись, связана с тем, что вы не создали индекс 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 });

У вас возникнет следующая проблема:

  1. ВСТАВИТЬ {email: 'me@email.com'}
  2. Попытка ВСТАВИТЬ {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 или более позднюю версию, частичные индексы следует отдавать предпочтение перед разреженными.

0 голосов
/ 06 июля 2018

Mongoose Предоставляет вам возможность иметь уникальные поля. И это возвращает ошибку, когда эти условия не соответствуют.

Например: E11000 duplicate key error index in mongodb mongoose

Вы можете обновить свой код как:

const UserSchema = new mongoose.Schema({
 email: {
  type: String,
  required: true,
  unique: true,
  trim: true
},
 username: {
  type: String,
  required: false,
  unique: true,
  trim: true
}
})
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...