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

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

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

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

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

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

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


person foobar    schedule 04.04.2011    source источник
comment
Плохие новости, это все еще проблема с mongod v2.4.3, mongoose v3.6.20   -  person damphat    schedule 21.10.2013
comment
Похоже, что Unique работает на одном из моих хостов, но не может применить уникальные методы, использующие точно такой же код узла / мангуста на другом хосте. Хост, который работает правильно, запускает один mongod 3.4.10, тот, который не работает, - запускает реплику, установленную с mongod 3.2.17. На обоих хостах я создаю коллекцию с нуля, поэтому существующие дубли не являются проблемой. Я пробовал большинство решений на этой странице, и то, что сработало, был mongoose-unique-validator от @Isaac Pak.   -  person Maksym    schedule 11.01.2018


Ответы (24)


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

person foobar    schedule 04.04.2011
comment
У меня такая же проблема, но я не могу понять, как перезапустить mongo на OSX. Когда я убиваю процесс, он просто автоматически появляется снова, а уникальный индекс все еще не работает ... какие-нибудь идеи? - person ragulka; 13.09.2012
comment
что ты имеешь в виду упс, тебе просто нужно перезапустить монго ?! Вы говорите, что невозможно добавить индекс без остановки базы данных? - person andrewrk; 13.12.2013
comment
Это неправда. Вам не нужно перезапускать mongo, чтобы добавить индекс. - person JohnnyHK; 09.12.2014
comment
за уникальную вещь .. Я должен был перезапустить монго .. и это сработало .. Спасибо! - person Muhammad Ahsan Ayaz; 01.02.2015
comment
Я попробовал перезапустить. Тоже переиндексация. Чтобы решить эту проблему, пришлось отбросить базу данных. Угадайте, что проблема в том, что дубликаты уже существовали до добавления индекса, поэтому в производственной базе данных мне нужно будет удалить дубликаты, а затем перезапустить? - person isimmons; 19.06.2015
comment
@isimmons, отбрасывающий коллекцию, сработал для меня. Спасибо за комментарий. - person Cole Murray; 07.05.2016
comment
Я перезапустил оба mongod и вышел из всех клиентов, затем перезапустил mongod, и у меня все еще такое же поведение. Я использую mongo v3.4.17 и mongoose 5.2.15. Однако я получаю предупреждения об устаревании в отношении collection.ensureIndex, и он говорит мне использовать вместо этого createIndexes, поэтому я тестирую Model.createIndexes () ... - person solstice333; 19.09.2018
comment
Команда перезапуска для mongodb в Windows: mongod --port 27017 --dbpath = E: \ data \ db \ - person Sanjeev Kumar; 30.10.2019

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

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

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

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

mongo <db-name>
> db.dropDatabase()
person jpillora    schedule 29.10.2012
comment
db.dropDatabase () стирает вашу базу данных! - person Isaac Pak; 21.03.2017

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

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

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

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

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

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

person Neil Strain    schedule 13.10.2016

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

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

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

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

person solstice333    schedule 18.09.2018
comment
Единственный ответ на вопрос, который касается проблемы, а не вращается вокруг нее. - person Saksham Gupta; 28.01.2019
comment
Этот ответ мне помог. Все, что мне не хватало, это index: true для создания моего уникального индекса. - person elcid; 16.02.2020

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

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

yourModel.on('index', function(err) {
  if (err?) {
    console.error(err)
  }
);
person Pierre Maoui    schedule 04.01.2014

Хорошо, я смог решить эту проблему из 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]\" }"
    }
})
person woj.sierak    schedule 10.12.2014

Согласно документации: 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})
person Damien Romito    schedule 04.08.2016
comment
Он говорит, что индекс падения, а не коллекция - person Zero0Ho; 12.02.2020

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

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

Это приведет к принудительному использованию уникального индекса для полей username и email в вашей UserSchema. Ваше здоровье.

person moeabdol    schedule 26.11.2017
comment
Немного поздно для вечеринки, но что хорошего в ORM, который немного неаккуратен при применении уникальных индексов - person Imre_G; 13.11.2018
comment
Что хорошего в принижающих комментариях, которые никоим образом не помогают. Это надежное решение, готовое к производству. - person Isaac Pak; 19.02.2019

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

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

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

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

person Derek Hill    schedule 15.03.2020


Действия по устранению проблемы:

1. Добавьте unique: true к атрибутам.

let schema = new mongoose.Schema(
    {
        name: {
            type: String,
            unique: true,
            required: [true, "name required."],
        }
    }
);

module.exports = mongoose.model("role", schema);

2. Отбросить коллекцию - например role (последняя строка)

  • Это простой способ исправить - если у вас уже есть повторяющиеся значения.
  • Вы также можете удалить все записи в коллекции, чтобы в уникальном столбце были повторяющиеся значения (name выше)

3. Перезапустите сервер Node.js, использующий библиотеку mongoose.


Как некоторые другие ответы здесь неверны?

  • Параметр autoIndex установлен на true

    • not required, by default it is true
  • Перезагрузите БД

    • not required, you only need to restart the Node.js server

  • Follow above 3 steps in sequence
    • If you miss anything, do it 2 times
person Manohar Reddy Poreddy    schedule 17.02.2021

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

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

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) дополнительные опции

  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.

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

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

person Isaac Pak    schedule 21.03.2017

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

person chen Jacky    schedule 19.10.2017

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

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

db.users.dropIndex('username_1');

person Ademola Adegbuyi    schedule 17.12.2015

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

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

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

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

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

person Rakin Afser    schedule 14.09.2017

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

person Lee Quinze    schedule 10.05.2019

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

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

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

User = new Schema ({
   email: {type: String, unique: true}
});
User.createIndexes();
person Samir Hosny    schedule 18.06.2019

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

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

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

person Rafael Mejía    schedule 18.08.2018

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

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

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

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

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

db.User.drop()
person Pulkit Aggarwal    schedule 18.06.2019

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

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

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

  7. Сохранять

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

person Balepur    schedule 08.07.2019
comment
что означает 1 здесь в объекте {email: 1}? - person siluveru kiran kumar; 04.06.2020

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

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

person Zero0Ho    schedule 12.02.2020

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

db.users.remove({})

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

person StefanBob    schedule 02.06.2020

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

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

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

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

person nick    schedule 20.08.2020

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

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

person nishant srivastava    schedule 25.08.2020
comment
Какую версию вы использовали? - person Baboo; 06.09.2020

Когда вы подключаете свою базу данных к приложению, добавьте эту опцию: 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, но у меня это не сработало.

person Hasan    schedule 11.10.2020