Mongoose Унікальний індекс не працює!


95

Я намагаюся дозволити MongoDB виявити повторюване значення на основі його індексу. Я думаю, що це можливо в MongoDB, але через обгортку Mongoose речі здаються зламаними. Отже, приблизно так:

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

Я можу врятувати 2 користувачів за допомогою тієї ж електронної пошти. Проклятий.

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

Наразі я вручну дзвоню на db, щоб знайти користувача. Цей дзвінок не є дорогим, оскільки "електронна пошта" індексується. Але все-таки було б непогано дозволити, щоб з цим поводились споконвічно.

Хтось має рішення цього?


1
Погана новина, це все ще проблема з mongod v2.4.3, mongoose v3.6.20
damphat

Унікальний, здається, працює на одному з моїх хостів, але не вдається застосувати унікальні, використовуючи точно той же код вузла / мангуста на іншому хості. Хост, який працює належним чином, запускає одиночний mongod 3.4.10, той, що цього не робить, - запускає набір реплік з mongod 3.2.17.На обох хостах я створюю колекцію з нуля, тому існуючі дупки не є проблемою. Я спробував більшість рішень на цій сторінці, і одне, що працювало, було унікальним валідатором мангуста від @Isaac Pak.
Максим

Відповіді:


94

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


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

7
що ви маєте на увазі "ой, просто треба перезапустити mongo" ?! Ви говорите, що неможливо додати індекс, не збиваючи базу даних?
andrewrk

7
Це неправда. Вам не потрібно перезапускати mongo, щоб додати індекс.
JohnnyHK

1
за унікальну річ .. Я МОГО перезапустити mongo .. і це спрацювало .. Дякую!
Мухаммед Ахсан Аяз

2
Я спробував перезапустити. Також переіндексація. Для вирішення цього довелося скинути базу даних. Вгадуючи проблему, дублікати вже існували до додавання індексу, тож у виробничій базі даних мені потрібно було б видалити дублікати, а потім перезапустити?
isimmons

40

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

І переіндексуйте теж, за допомогою:

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

Під час тестування, оскільки у мене немає важливих даних, ви також можете зробити:

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

16
db.dropDatabase () стирає вашу базу даних!
Ісаак Пак,

28

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

1) Видаліть усі документи з колекції користувачів.

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

Щодо кроку 1, зверніть увагу, що з документів Монго:

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

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


11

Така поведінка трапляється також, якщо ви залишили кілька копій у Монго. Mongoose спробує створити їх у Mongo під час запуску вашої програми.

Щоб цього не сталося, ви можете вирішити цю помилку таким чином:

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

10

Гаразд, мені вдалося вирішити це з монгошелли, додавши індекс у поле та встановивши унікальну властивість:

db.<collectionName>.ensureIndex({fieldName: 1}, {unique: true});

Shell повинен відповісти таким чином:

{
    "createdCollectionAutomatically" : false,
    "numIndexesBefore" : 1,
    "numIndexesAfter" : 2,
    "ok" : 1
}

Тепер для швидкого тестування з монгошелли:

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()це асинхронно, але AFAIK, здається, працює нормально


Єдина відповідь на питання, яке стосується проблеми, а не обертається навколо неї.
Сакшам Гупта

Ця відповідь мені допомогла. Мені бракувало лише index: trueстворення мого унікального індексу.
elcid

6

Відповідно до документації: https://docs.mongodb.com/v2.6/tutorial/modify-an-index/

Щоб змінити існуючий індекс, потрібно скинути та відтворити індекс.

НЕ РЕСТАРТУЙТЕ МОНГО!

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, який "трохи вільний при застосуванні унікальних індексів"
Imre_G

Що хорошого в приниженні коментарів, які жодним чином не допомагають. Це рішення міцне і готове до виробництва.
Ісаак Пак,

4

Mongoose мовчки не зможе додати унікальний індекс, якщо:

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

У першому випадку перелічіть індекси за допомогою db.collection.getIndexes()та відкиньте старий індекс за допомогою db.collection.dropIndex("index_name"). Коли ви перезапускаєте програму Mongoose, вона повинна правильно додати новий індекс.

У другому випадку вам потрібно видалити дублікати перед перезапуском програми 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 тут в об’єкті "електронна пошта": 1}?
siluveru kiran kumar

0

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

Потім просто перезапустіть програму (мангуст). Це просто мовчки додавання індексу не вдається.


0

Вилучення всіх документів із колекції:

db.users.remove({})

І перезапуск, як згадували інші, у мене спрацював


0

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

Це досить дивно, оскільки для деяких користувачів працювало лише скидання однієї колекції. Деяким з них просто потрібно було скинути базу даних. Але це не спрацювало у мене. Я скинув базу даних, а потім перезапустив службу MongoDB Server.

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

Якщо інші методи у вас не спрацювали, я вважаю, це зробить свою справу.


0

У моєму випадку мангуст був застарілим. я перевірив це, запустивши npm застарілий на 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.