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


95

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

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

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

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

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

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


1
Плохие новости, проблема с mongod v2.4.3, mongoose v3.6.20 по-
прежнему

Похоже, что Unique работает на одном из моих хостов, но не может применить уникальные методы с использованием точно такого же кода узла / мангуста на другом хосте. Хост, который работает правильно, запускает один mongod 3.4.10, тот, который не работает, - запускает реплику, установленную с mongod 3.2.17. На обоих хостах я создаю коллекцию с нуля, поэтому существующие дубли не являются проблемой. Я пробовал большинство решений на этой странице, и то, что сработало, - это mongoose-unique-validator от @Isaac Pak.
Максим

Ответы:


94

Ой! Вам просто нужно перезапустить mongo.


4
У меня такая же проблема, но я не могу понять, как перезапустить mongo на OSX. Когда я завершаю процесс, он просто автоматически появляется снова, а уникальный индекс все еще не работает ... какие-нибудь идеи?
ragulka

7
что ты имеешь в виду "ой, тебе просто нужно перезапустить монго" ?! вы говорите, что невозможно добавить индекс без остановки базы данных?
andrewrk

7
Это неправда. Вам не нужно перезапускать mongo, чтобы добавить индекс.
JohnnyHK

1
за уникальную вещь .. Мне пришлось перезапустить монго .. и это сработало .. Спасибо!
Мухаммад Ахсан Аяз

2
Я попытался перезапустить. Тоже переиндексация. Чтобы решить эту проблему, пришлось отбросить базу данных. Угадайте, что проблема в том, что дубликаты уже существовали до добавления индекса, поэтому в производственной базе данных мне нужно будет удалить дубликаты, а затем перезапустить?
isimmons,

40

Ой! Вам просто нужно перезапустить mongo.

И переиндексируйте тоже:

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

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

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

16
db.dropDatabase () стирает вашу базу данных!
Isaac Pak

28

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

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

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

Что касается шага 1, обратите внимание, что из документов Mongo:

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

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


11

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

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

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

10

Хорошо, я смог решить это из 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: { : \"martyna@martycud.com\" }"
    }
})

10

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

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 и получал следующее предупреждение об устаревании при запуске кода:

(node:21553) DeprecationWarning: collection.ensureIndex is deprecated. Use createIndexes instead.

Я не уверен, что Foo.createIndexes()это асинхронно, но, похоже, все работает нормально.


Единственный ответ на вопрос, который касается проблемы, а не вращается вокруг нее.
Сакшам Гупта

Этот ответ мне помог. Все, что мне не хватало, - это index: trueсоздание моего уникального индекса.
elcid

6

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

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

НЕ ПЕРЕЗАПУСКАТЬ MONGO!

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

db.users.drop()

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

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

В нем говорится, что индекс падения, а не коллекция
Zero0Ho,

5

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

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

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


5
Немного поздно для вечеринки, но что хорошего в ORM, который «немного
свободен

Что хорошего в принижающих комментариях, которые никоим образом не помогают. Это надежное решение, готовое к производству.
Исаак Пак

4

Mongoose автоматически не сможет добавить уникальный индекс, если:

  1. В коллекции уже есть указатель с таким же названием
  2. В коллекции уже есть документы с дубликатами проиндексированного поля.

В первом случае укажите индексы с помощью db.collection.getIndexes()и отбросьте старый индекс с помощью db.collection.dropIndex("index_name"). Когда вы перезапустите приложение Mongoose, оно должно правильно добавить новый index.

Во втором случае вам нужно удалить дубликаты перед перезапуском приложения Mongoose.


3

мангуст-уникальный-валидатор

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

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: 'old-email@example.com' },
      { email: 'new-email@example.com' },
      { runValidators: true, context: 'query' },
      function(err) {
        // ...
    }

4) дополнительные опции

  1. без учета регистра

    используйте опцию uniqueCaseInsensitive в своей схеме

    ie. email: { type: String, index: true, unique: true, required: true, uniqueCaseInsensitive: true }

  2. пользовательские сообщения об ошибках

    ie. exampleSchema.plugin(uniqueValidator, { message: 'Error, expected {PATH} to be unique.' });

Теперь вы можете добавлять / удалять уникальное свойство в свои схемы, не беспокоясь о перезапуске mongo, удалении баз данных или создании индексов.

Предостережения (из документов):

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

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

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


2

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


1

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

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

db.users.dropIndex('username_1');


1

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

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

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

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

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


1

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


1

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

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

так что код будет таким.

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

0

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

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

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


0

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

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

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

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

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

db.User.drop()

0

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

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

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

  7. Сохранить

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


что означает 1 здесь в объекте {"email": 1}?
Силуверу Киран Кумар,

0

Убедитесь, что в вашей коллекции нет повторяющегося поля, в которое вы только что добавили уникальный индекс.

Затем просто перезапустите свое приложение (мангуст). Просто незаметно добавить индекс не удается.


0

Удаление всех документов из коллекции:

db.users.remove({})

И перезапуск, как упоминали другие, сработал для меня


0

Если ваш MongoDB работает как служба (простой способ найти это, если вам не нужно подключаться к базе данных без запуска файла mongod.exe через терминал), то после внесения изменений вам может потребоваться перезапустить службу и / или полностью отказаться от базы данных.

Это довольно странно, потому что для некоторых пользователей работало просто удаление одной коллекции. Некоторым из них просто нужно было сбросить базу данных. Но у меня это не сработало. Я удалил базу данных, а затем перезапустил службу MongoDB Server.

Чтобы перезапустить службу поиска Службы на панели поиска Windows, затем найдите службу MongoDB, дважды щелкните, чтобы открыть, затем остановите и снова запустите службу.

Если другие методы не помогли вам, я считаю, что это сработает.


0

В моем случае мангуст устарел. Я проверил это, запустив npm outdated на CMD. и обновил "мангуст".

Скажите, сработало ли это и для вас?


Какую версию вы использовали?
Baboo_

0

Когда вы подключаете свою базу данных к приложению, добавьте эту опцию: «audoIndex: true», например, в моем коде я сделал это:

const options = {
// your options go here
...
// this code is the solution
audoIndex: true
}
mongoose.connect(DB_URI, options);

Я также отбросил коллекцию, с которой у меня возникла проблема, и воссоздал ее, чтобы убедиться, что она будет работать. Я нашел это решение по адресу: https://dev.to/emmysteven/solved-mongoose-unique-index-not-working-45d5. Я также пробовал такие решения, как «перезапустить MongoDB», но у меня это не сработало.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.