¡El índice único de Mongoose no funciona!

Intento dejar que MongoDB detecte un valor duplicado según su índice. Creo que esto es posible en MongoDB, pero a través del contenedor Mongoose las cosas parecen estar rotas. Entonces para algo como esto:

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

Puedo guardar 2 usuarios con el mismo correo electrónico. Maldito.

El mismo problema se ha expresado aquí: https://github.com/LearnBoost/mongoose/issues/56 , pero ese hilo es antiguo y no conduce a nada.

Por ahora, estoy haciendo una llamada manual a la base de datos para encontrar al usuario. Esa llamada no es costosa ya que el “correo electrónico” está indexado. Pero aún sería bueno dejar que se maneje de forma nativa.

¿Alguien tiene una solución para esto?

Oops! Solo tienes que reiniciar mongo.

Oops! Solo tienes que reiniciar mongo.

¡Y volver a indexar también!

En las pruebas, acabo de hacer un:

 mongo  > db.dropDatabase() 

Aunque si tienes datos importantes allí, probablemente solo necesites:

 mongo  > db..reIndex() 

Me encontré con el mismo problema: agregué la restricción única para el campo de email a nuestro UserSchema después de haber agregado usuarios a la base de datos, y todavía era capaz de salvar a los usuarios con correos duplicados. Lo resolví haciendo lo siguiente:

1) Eliminar todos los documentos de la colección de usuarios.

2) Desde el shell de mongo, ejecute el comando: db.users.createIndex({email: 1}, {unique: true})

Con respecto al paso 1, ten en cuenta que de los documentos de Mongo:

MongoDB no puede crear un índice único en los campos de índice especificados si la colección ya contiene datos que violarían la restricción única para el índice.

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

Este comportamiento también ocurre si ha dejado algunos duplicados en Mongo. Mongoose intentará crearlos en Mongo cuando se inicie tu aplicación.

Para evitar esto, puede manejar este error de esta manera:

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

Ok, pude resolver esto desde mongoshell agregando el índice en el campo y estableciendo la propiedad única:

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

Shell debería responder de esta manera:

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

Ahora para probar rápidamente de la mongoshell:

 var doc = {fieldName: 'abc'}; db..insert(doc) 

Debería dar: WriteResult ({“nInserted”: 1})

Pero cuando repito de nuevo:

 db..insert(doc) 

Daré:

 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\" }" } }) 

Según la documentación: https://docs.mongodb.com/v2.6/tutorial/modify-an-index/

Para modificar un índice existente, debe soltar y volver a crear el índice.

NO REINICIAR MONGO!

1 – soltar la colección

 db.users.drop() 

2 – reindexar la tabla

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

Mangosta es un poco flexible cuando se aplican índices únicos desde el nivel de aplicación; por lo tanto, es preferible imponer sus índices únicos desde la base de datos usando el mongo cli o explícitamente decirle a mongoose que usted es serio acerca del índice unique al escribir la siguiente línea de código justo después de su UserSchema:

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

Esto aplicará el índice único en los campos de username y email en su UserSchema. Aclamaciones.

También puede resolver este problema al descartar el índice;

supongamos que desea eliminar el índice exclusivo de los users colección y el username campo, escriba esto:

db.users.dropIndex('username_1');

Si la tabla / colección está vacía, cree un índice único para el campo:

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

Si la tabla / colección no está vacía, suelte la colección y cree el índice:

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

Ahora reinicie mongoDB.

La respuesta más reciente: no hay necesidad de reiniciar mongodb, si colleciton ya tiene índices del mismo nombre, la mongoose no volverá a crear los índices, por lo tanto, suelte los índices existentes de la recostackción y ahora, cuando ejecute la mongoose, creará un nuevo índice , el proceso anterior resolvió mi problema.

mongoose-unique-validator

Cómo usar este plugin:

1) instalación de npm –save mongoose-unique-validator

2) en su esquema siga esta guía:

 // 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) métodos de mongoose

Al utilizar métodos como findOneAndUpdate , deberá pasar este objeto de configuración:

{ runValidators: true, context: 'query' }

 ie. User.findOneAndUpdate( { email: 'old-email@example.com' }, { email: 'new-email@example.com' }, { runValidators: true, context: 'query' }, function(err) { // ... } 

4) opciones adicionales

  1. case insensible

    use la opción uniqueCaseInsensitive en su esquema

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

  2. mensajes de error personalizados

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

Ahora puede agregar / eliminar la propiedad única de sus esquemas sin preocuparse por reiniciar mongo, descartar bases de datos o crear índices.

Advertencias (de los documentos):

Debido a que confiamos en las operaciones asincrónicas para verificar si un documento existe en la base de datos, es posible que se ejecuten dos consultas al mismo tiempo, ambas devuelven 0 y luego ambas se insertan en MongoDB.

Aparte de bloquear automáticamente la colección o forzar una sola conexión, no hay una solución real.

Para la mayoría de nuestros usuarios, esto no será un problema, pero es un caso extremo a tener en cuenta.

Si está utilizando la opción autoIndex: false en el método de conexión de esta manera:

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

Intenta eliminar eso. Si eso no funciona, intente reiniciar mongodb como muchos sugirieron en este hilo.