Ответ 1
Oops! Вам просто нужно перезапустить манго.
Я пытаюсь позволить MongoDB обнаруживать дублирующее значение на основе его индекса. Я думаю, что это возможно в MongoDB, но через оболочку Mongoose, похоже, сломаны. Итак, что-то вроде этого:
User = new Schema ({
email: {type: String, index: {unique: true, dropDups: true}}
})
Я могу сохранить 2 пользователей с тем же адресом электронной почты. Чёрт.
Эта же проблема была выражена здесь: https://github.com/LearnBoost/mongoose/issues/56, но эта ветка старая и ведет к никуда.
Теперь я вручную звоню в db, чтобы найти пользователя. Этот вызов не стоит дорого, так как индексируется "электронная почта". Но было бы неплохо позволить, чтобы это было обработано изначально.
Есть ли у кого-нибудь решение?
Oops! Вам просто нужно перезапустить манго.
К сожалению! Вам просто нужно перезапустить Монго.
И переиндексировать тоже, с помощью:
mongo <db-name>
> db.<collection-name>.reIndex()
При тестировании, поскольку у меня нет важных данных, вы также можете сделать следующее:
mongo <db-name>
> db.dropDatabase()
Я столкнулся с той же проблемой: я добавил уникальное ограничение для поля email
в наш UserSchema
после того, как добавил пользователей в db и по-прежнему мог сохранять пользователей с помощью сообщений об ошибках. Я решил это, выполнив следующие действия:
1) Удалите все документы из коллекции пользователей.
2) Из оболочки mongo выполните команду:
db.users.createIndex({email: 1}, {unique: true})
Относительно шага 1 обратите внимание, что из Mongo docs:
MongoDB не может создать уникальный индекс в указанном поле индекса (ов), если коллекция уже содержит данные, которые будут нарушать уникальное ограничение для индекса.
Такое поведение происходит также, если вы оставили некоторые дубликаты в Mongo. Mongoose попытается создать их в Mongo, когда ваше приложение запустится.
Чтобы предотвратить это, вы можете обрабатывать эту ошибку следующим образом:
yourModel.on('index', function(err) {
if (err?) {
console.error err
}
);
Хорошо, я смог разрешить это из mongoshell, добавив индекс в поле и установив уникальное свойство:
db.<collectionName>.ensureIndex({fieldName: 1}, {unique: true});
Shell должна ответить следующим образом:
{
"createdCollectionAutomatically" : false,
"numIndexesBefore" : 1,
"numIndexesAfter" : 2,
"ok" : 1
}
Теперь, чтобы быстро протестировать mongoshell:
var doc = {fieldName: 'abc'};
db.<collectionName>.insert(doc)
Должен дать: WriteResult ({ "nInserted": 1})
Но при повторении снова:
db.<collectionName>.insert(doc)
Дает:
WriteResult({
"nInserted" : 0,
"writeError" : {
"code" : 11000,
"errmsg" : "insertDocument :: caused by :: 11000 E11000 duplicate key error index: fuelConsumption.users.$email_1 dup key: { : \"[email protected]\" }"
}
})
Mongoose немного ослаблен при применении уникальных индексов на уровне приложений; поэтому он предпочитал либо применять ваши уникальные индексы из самой базы данных, используя mongo cli, либо явно указывать mongoose, что вы серьезно относитесь к индексу unique
, написав следующую строку кода сразу после вашего UserSchema:
UserSchema.index({ username: 1, email: 1 }, { unique: true});
Это обеспечит уникальный индекс для полей username
и email
в вашей UserSchema. Приветствия.
Согласно документации: https://docs.mongodb.com/v2.6/tutorial/modify-an-index/
Чтобы изменить существующий индекс, вам нужно отбросить и воссоздать индекс.
НЕ ОТПУСКАЙТЕ МОНГО!
1 - отбросить коллекцию
db.users.drop()
2 - переиндексировать таблицу
db.users.ensureIndex({email: 1, type: 1}, {unique: true})
Я сделал что-то вроде этого:
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const FooSchema = new Schema({
name: { type: String, required: true, index: true, unique: true }
});
const Foo = mongoose.model('Foo', FooSchema);
Foo.createIndexes();
module.exports = Foo
Я добавил Foo.createIndexes()
bc. При Foo.createIndexes()
я получал следующее предупреждение об устаревании:
(node:21553) DeprecationWarning: collection.ensureIndex is deprecated. Use createIndexes instead.
Я не уверен, что Foo.createIndexes()
является асинхронным, но AFAIK кажется, что все работает нормально
Как использовать этот плагин:
1) npm install --save mongoose-unique-validator
2) в вашей схеме следуйте этому руководству:
// declare this at the top
var mongoose = require('mongoose');
var uniqueValidator = require('mongoose-unique-validator');
// exampleSchema = mongoose.Schema({}) etc...
exampleSchema.plugin(uniqueValidator);
// module.exports = mongoose.model(...) etc....
3) методы мангуста
При использовании таких методов, как findOneAndUpdate
, вам необходимо передать этот объект конфигурации:
{ runValidators: true, context: 'query' }
ie. User.findOneAndUpdate(
{ email: '[email protected]' },
{ email: '[email protected]' },
{ runValidators: true, context: 'query' },
function(err) {
// ...
}
4) дополнительные опции
нечувствительность к регистру
используйте параметр uniqueCaseInsensitive в вашей схеме
ie. email: { type: String, index: true, unique: true, required: true, uniqueCaseInsensitive: true }
сообщения об ошибках
ie. exampleSchema.plugin(uniqueValidator, { message: 'Error, expected {PATH} to be unique.' });
Теперь вы можете добавить/удалить уникальное свойство в свои схемы, не беспокоясь о перезапуске монго, удалении баз данных или создании индексов.
Предостережения (из документов):
Поскольку мы полагаемся на операции async, чтобы проверить, существует ли документ в базе данных, возможно одновременное выполнение двух запросов, оба возвращаются обратно, а затем оба вставляются в MongoDB.
Вне автоматической блокировки коллекции или принудительного единственного соединения нет реального решения.
Для большинства наших пользователей это не будет проблемой, но это краевой вопрос, о котором нужно знать.
Вы также можете устранить эту проблему, отбросив индекс;
допустим, что вы хотите удалить уникальный индекс из коллекции users
и поля username
, введите это:
db.users.dropIndex('username_1');
Если таблица/коллекция пуста, создайте уникальный индекс для поля:
db.<collection_name>.createIndex({'field':1}, {unique: true})
Если таблица/коллекция не пуста, отбросьте коллекцию и создайте индекс:
db.<collection_name>.drop()
db.<collection_name>.createIndex({'field':1}, {unique: true})
Теперь перезапустите mongoDB.
Самый новый ответ: нет необходимости перезапускать mongodb вообще, если у коллектива уже есть те же самые имена, мангуст не воссоздает ваши индексы снова, поэтому, сначала снимите собранные индексы, и теперь, когда вы запускаете мангуст, он создаст новый индекс, выше процесс решил мою проблему.
проверьте, что autoIndex в схеме имеет значение true, может быть установлено false (по умолчанию true), когда вы используете параметры mongoose.connect
Если вы используете опцию autoIndex: false
в методе подключения следующим образом:
mongoose.connect(CONNECTION_STRING, { autoIndex: false });
Попробуйте удалить это. Если это не сработает, попробуйте перезапустить mongodb, как многие предложили в этой теме.
Вы можете определить свою схему как
User = new Schema ({
email: {
type: String,
unique: true
}
})
Но, возможно, это не сработает, когда документ уже существует, и после этого вы изменили схему пользователя. Вы можете создать индекс по электронной почте для этой коллекции пользователей, если не хотите удалять коллекцию. С помощью этой команды вы можете создать индекс по электронной почте.
db.User.createIndex({email:1},{unique: true})
Или вы можете просто удалить коллекцию и снова добавить пользователя.
Для удаления коллекции вы можете ввести это:
db.User.drop()
createIndexes()
время я сталкивался с той же проблемой и много занимался поиском, и решением для меня была createIndexes()
.
Я хочу, чтобы это помогло.
поэтому код будет таким.
User = new Schema ({
email: {type: String, unique: true}
});
User.createIndexes();
Когда я столкнулся с этой проблемой, я попытался удалить базу данных, многократно перезапуская сервер (nodemon), и ни один из приемов не работал вообще. Я нашел следующую работу через Robo 3T:
_id_
по умолчанию. Теперь выберите Добавить индексemail
электронной почты для поля электронной почты, напримерПредоставьте ключи как JSON. Например
{
"email": 1
}
Нажмите на флажок Уникальный
Это гарантирует, что в MongoDB не будут сохранены дублирующиеся электронные письма.