Подтвердить что ты не робот

Mongoose Уникальный индекс не работает!

Я пытаюсь позволить MongoDB обнаруживать дублирующее значение на основе его индекса. Я думаю, что это возможно в MongoDB, но через оболочку Mongoose, похоже, сломаны. Итак, что-то вроде этого:

User = new Schema ({
  email: {type: String, index: {unique: true, dropDups: true}}
})

Я могу сохранить 2 пользователей с тем же адресом электронной почты. Чёрт.

Эта же проблема была выражена здесь: https://github.com/LearnBoost/mongoose/issues/56, но эта ветка старая и ведет к никуда.

Теперь я вручную звоню в db, чтобы найти пользователя. Этот вызов не стоит дорого, так как индексируется "электронная почта". Но было бы неплохо позволить, чтобы это было обработано изначально.

Есть ли у кого-нибудь решение?

4b9b3361

Ответ 1

Oops! Вам просто нужно перезапустить манго.

Ответ 2

  К сожалению! Вам просто нужно перезапустить Монго.

И переиндексировать тоже, с помощью:

mongo <db-name>
> db.<collection-name>.reIndex()

При тестировании, поскольку у меня нет важных данных, вы также можете сделать следующее:

mongo <db-name>
> db.dropDatabase()

Ответ 3

Я столкнулся с той же проблемой: я добавил уникальное ограничение для поля email в наш UserSchema после того, как добавил пользователей в db и по-прежнему мог сохранять пользователей с помощью сообщений об ошибках. Я решил это, выполнив следующие действия:

1) Удалите все документы из коллекции пользователей.

2) Из оболочки mongo выполните команду: db.users.createIndex({email: 1}, {unique: true})

Относительно шага 1 обратите внимание, что из Mongo docs:

MongoDB не может создать уникальный индекс в указанном поле индекса (ов), если коллекция уже содержит данные, которые будут нарушать уникальное ограничение для индекса.

https://docs.mongodb.com/manual/core/index-unique/

Ответ 4

Такое поведение происходит также, если вы оставили некоторые дубликаты в Mongo. Mongoose попытается создать их в Mongo, когда ваше приложение запустится.

Чтобы предотвратить это, вы можете обрабатывать эту ошибку следующим образом:

yourModel.on('index', function(err) {
  if (err?) {
    console.error err
  }
);

Ответ 5

Хорошо, я смог разрешить это из 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]\" }"
    }
})

Ответ 6

Mongoose немного ослаблен при применении уникальных индексов на уровне приложений; поэтому он предпочитал либо применять ваши уникальные индексы из самой базы данных, используя mongo cli, либо явно указывать mongoose, что вы серьезно относитесь к индексу unique, написав следующую строку кода сразу после вашего UserSchema:

UserSchema.index({ username: 1, email: 1 }, { unique: true});

Это обеспечит уникальный индекс для полей username и email в вашей UserSchema. Приветствия.

Ответ 7

Согласно документации: https://docs.mongodb.com/v2.6/tutorial/modify-an-index/

Чтобы изменить существующий индекс, вам нужно отбросить и воссоздать индекс.

НЕ ОТПУСКАЙТЕ МОНГО!

1 - отбросить коллекцию

db.users.drop()

2 - переиндексировать таблицу

db.users.ensureIndex({email: 1, type: 1}, {unique: true})

Ответ 8

Я сделал что-то вроде этого:

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 кажется, что все работает нормально

Ответ 9

mongoose-unique-validator

Как использовать этот плагин:

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.

Вне автоматической блокировки коллекции или принудительного единственного соединения нет реального решения.

Для большинства наших пользователей это не будет проблемой, но это краевой вопрос, о котором нужно знать.

Ответ 10

Вы также можете устранить эту проблему, отбросив индекс;

допустим, что вы хотите удалить уникальный индекс из коллекции users и поля username, введите это:

db.users.dropIndex('username_1');

Ответ 11

Если таблица/коллекция пуста, создайте уникальный индекс для поля:

db.<collection_name>.createIndex({'field':1}, {unique: true})

Если таблица/коллекция не пуста, отбросьте коллекцию и создайте индекс:

db.<collection_name>.drop()
db.<collection_name>.createIndex({'field':1}, {unique: true})

Теперь перезапустите mongoDB.

Ответ 12

Самый новый ответ: нет необходимости перезапускать mongodb вообще, если у коллектива уже есть те же самые имена, мангуст не воссоздает ваши индексы снова, поэтому, сначала снимите собранные индексы, и теперь, когда вы запускаете мангуст, он создаст новый индекс, выше процесс решил мою проблему.

Ответ 13

проверьте, что autoIndex в схеме имеет значение true, может быть установлено false (по умолчанию true), когда вы используете параметры mongoose.connect

Ответ 14

Если вы используете опцию autoIndex: false в методе подключения следующим образом:

mongoose.connect(CONNECTION_STRING, { autoIndex: false });

Попробуйте удалить это. Если это не сработает, попробуйте перезапустить mongodb, как многие предложили в этой теме.

Ответ 15

Вы можете определить свою схему как

User = new Schema ({
  email: {
      type: String,
      unique: true
  }
})

Но, возможно, это не сработает, когда документ уже существует, и после этого вы изменили схему пользователя. Вы можете создать индекс по электронной почте для этой коллекции пользователей, если не хотите удалять коллекцию. С помощью этой команды вы можете создать индекс по электронной почте.

db.User.createIndex({email:1},{unique: true})

Или вы можете просто удалить коллекцию и снова добавить пользователя.
Для удаления коллекции вы можете ввести это:

db.User.drop()

Ответ 16

createIndexes() время я сталкивался с той же проблемой и много занимался поиском, и решением для меня была createIndexes().

Я хочу, чтобы это помогло.

поэтому код будет таким.

User = new Schema ({
   email: {type: String, unique: true}
});
User.createIndexes();

Ответ 17

Когда я столкнулся с этой проблемой, я попытался удалить базу данных, многократно перезапуская сервер (nodemon), и ни один из приемов не работал вообще. Я нашел следующую работу через Robo 3T:

  1. В Robo 3T дважды щелкните по базе данных, чтобы открыть коллекции
  2. Откройте коллекции, чтобы открыть коллекцию, о которой идет речь. Убедитесь, что ваши коллекции пусты, для начала
  3. Щелкните правой кнопкой мыши на папке индексов. По умолчанию вы увидите _id_ по умолчанию. Теперь выберите Добавить индекс
  4. Выберите имя, например, email электронной почты для поля электронной почты, например
  5. Предоставьте ключи как JSON. Например

    {
       "email": 1
    }
    
  6. Нажмите на флажок Уникальный

  7. Сохранить

Это гарантирует, что в MongoDB не будут сохранены дублирующиеся электронные письма.