Índice único en MongoDB

Tahseen Tauseef 12 octubre 2023
  1. Índice único en MongoDB
  2. Comportamiento del índice único en MongoDB
  3. Validar correos electrónicos únicos con Mongoose
Índice único en MongoDB

En este tutorial, aprenderá sobre índices únicos, incluidos qué son y cómo crearlos en MongoDB. Además, se describe brevemente el proceso de hacer que el correo electrónico de un usuario sea único en MongoDB.

El índice de este artículo es el siguiente:

  1. Índices únicos en MongoDB
  2. Crea un índice único en MongoDB
  3. Comportamiento de índices únicos en MongoDB
  4. Validar correos electrónicos únicos con Mongoose

Índice único en MongoDB

Un índice único garantiza que los campos indexados no contengan valores duplicados, lo que garantiza que los campos indexados sean únicos. Durante la construcción de una colección, MongoDB produce un índice único en la columna _id por defecto.

Utilice el comando db.collection.createIndex() para generar un índice único con la opción unique establecida en true.

db.collection.createIndex( <key and index type specification>, { unique: true } )

Índice único en un solo campo

Utilice el siguiente procedimiento en mongosh para crear un índice único en el campo user_id de la colección members.

db.members.createIndex( { "user_id": 1 }, { unique: true } )

Índice compuesto único

En los índices compuestos, también puede imponer una restricción única. Por ejemplo, MongoDB impone la unicidad en la combinación de valores de clave de índice si emplea la restricción única en un índice compuesto.

Utilice la siguiente operación en mongosh para crear un índice único en los campos groupNumber, lastname y firstname de la colección members.

db.members.createIndex( { groupNumber: 2, lastname: 1, firstname: 1 }, { unique: true } )

El índice garantiza que cada combinación de valores groupNumber, lastname y firstname sea única.

Considere la siguiente colección con el siguiente documento.

{ _id: 1, a: [ { loc: "A", qty: 5 }, { qty: 10 } ] }

Cree un índice multiclave compuesto único en a.loc y a.qty.

db.collection.createIndex( { "a.loc": 1, "a.qty": 1 }, { unique: true } )

Los siguientes documentos se pueden incluir en la colección porque el índice garantiza la unicidad para la combinación de los valores a.loc y a.qty.

db.collection.insertMany( [
   { _id: 2, a: [ { loc: "A" }, { qty: 6 } ] },
   { _id: 3, a: [ { loc: "A", qty: 12 } ] }
] )

Comportamiento del índice único en MongoDB

Restricciones:

Si la colección ya incluye datos que violarían el requisito único del índice, MongoDB no podrá establecer un índice único en los campos de índice proporcionados. En un índice hash, no puede definir una restricción única.

Utilice conjuntos de réplicas y clústeres fragmentados para crear un índice único

El uso de una operación continua para generar un índice único en conjuntos de réplicas y clústeres fragmentados requiere detener todas las escrituras en la colección durante todo el procedimiento.

No utilice la operación continua si no puede detener todas las escrituras en la colección durante el procedimiento. En su lugar, cree un índice único para la colección emitiendo:

  1. db.collection.createIndex() en el principal para un conjunto de réplicas
  2. db.collection.createIndex() en mongos para un clúster fragmentado

Restricción única en documentos separados

El requisito de ser único se aplica a cada documento de la colección. El índice único evita que la clave indexada tenga el mismo valor en diferentes documentos.

Debido a que la limitación solo se aplica a documentos separados, un documento puede tener una matriz de elementos que dan como resultado valores de clave de índice repetidos para un índice de múltiples claves único, siempre que los valores de clave de índice para el documento no dupliquen los de otro documento. La entrada de índice repetida solo se ingresa una vez en el índice en este escenario.

Por ejemplo, una colección que contiene los siguientes documentos.

{ _id: 1, a: [ { loc: "A", qty: 6 }, { qty: 10 } ] }
{ _id: 2, a: [ { loc: "A" }, { qty: 7 } ] }
{ _id: 3, a: [ { loc: "A", qty: 12 } ] }

Cree un índice multiclave compuesto único en a.loc y a.qty.

db.collection.createIndex( { "a.loc": 1, "a.qty": 1 }, { unique: true } )

Si ningún otro documento en esa colección tiene un valor de clave de índice de {"a.loc": "B", "a.qty": null}, el índice único permite insertar el siguiente documento en la colección.

db.collection.insertOne( { _id: 4, a: [ { loc: "B" }, { loc: "B" } ] } )

Índice único y campo faltante

Si un documento en un índice único no contiene un valor para el campo indexado, el índice almacenará un valor nulo para ese documento. MongoDB solo permitirá que falte un documento en la columna indexada debido a la restricción única.

La creación del índice fallará con un error de clave duplicada si hay más de un documento sin valor para el campo indexado o si falta el campo indexado.

Una colección, por ejemplo, tiene un índice único en x.

db.collection.createIndex( { "x": 13 }, { unique: true } )

Si la colección aún no incluye un documento al que le falta el campo x, el índice único permite la inserción de un documento sin el campo x.

db.collection.insertOne( { y: 2 } )

Sin embargo, si la colección ya tiene un documento sin campo x, el índice único fallará al insertar un documento sin campo x.

db.collection.insertOne( { z: 2 } )

La operación no puede insertar el documento debido a una violación de la restricción única en el valor del campo x.

WriteResult({
   "nInserted" : 0,
   "writeError" : {
      "code" : 12000,
      "errmsg" : "E12000 duplicate key error index: test.collection.$a.b_1 dup key: { : null }"
   }
})

Índice parcial único

Solo los documentos de una colección que coinciden con una expresión de filtro particular se indexan en índices parciales. Por lo tanto, si usa una expresión de filtro parcial y una restricción única, la restricción única solo se aplica a los documentos que coinciden con la expresión de filtro.

Si los documentos no cumplen con los requisitos del filtro, un índice parcial con una restricción única no prohíbe la inserción de documentos que no cumplan con la restricción única.

Clústeres fragmentados e índice único

En un índice hash, no puede definir una restricción única.

Solo los siguientes índices pueden ser únicos en una colección fragmentada a distancia.

  1. El valor de índice de la clave de fragmento.
  2. Un índice compuesto con un prefijo como clave de partición.
  3. El índice predeterminado _id; sin embargo, el índice _id solo aplica el requisito de exclusividad por fragmento si los campos _id no son la clave de fragmento o el prefijo de clave de fragmento.

Las restricciones de índice único significan que:

  1. No puede fragmentar la colección si la colección tiene otros índices únicos para una colección que se fragmentará.
  2. No puede crear índices únicos para una colección ya fragmentada en otros campos.

Índice único disperso y no disperso

A partir de MongoDB 5.0, una sola colección puede tener índices dispersos y no dispersos únicos con el mismo patrón clave.

Creación de índices únicos y dispersos

En este ejemplo, se crean múltiples índices con el mismo patrón de clave y diferentes opciones “escasas”.

db.scores.createIndex( { score : 2 }, { name: "unique_index", unique: true } )
db.scores.createIndex( { score : 2 }, { name: "unique_sparse_index", unique: true, sparse: true } )

Creación de índices básicos y dispersos

Con y sin la opción disperso, puede construir índices simples con el mismo patrón clave.

db.scores.createIndex( { score : 2 }, { name: "sparse_index", sparse: true } )
db.scores.createIndex( { score : 2 }, { name: "basic_index" } )

Duplicar patrones clave en índices básicos y únicos

Con MongoDB 5.0, puede tener índices básicos y únicos con el mismo patrón clave. Debido a la duplicación de patrones clave, es posible agregar un índice único a campos ya indexados.

Ejemplo:

Haz un índice básico con el patrón clave { score: 2 } e inserta tres documentos.

db.scores.createIndex( { score : 1 }, { name: "basic_index" } )
db.scores.insert( { score : 1 } )
db.scores.insert( { score : 2 } )
db.scores.insert( { score : 4 } )

Cree un índice único con el mismo patrón clave { score: 2 }.

db.scores.createIndex( { score : 2 }, { name: "unique_index", unique: true } )

Intentar insertar un documento de partitura duplicado falla debido al índice único.

db.scores.insert( { score : 4 } )

Validar correos electrónicos únicos con Mongoose

Con Mongoose, puede evitar duplicados en sus bases de datos mediante la validación. La validación se define en el tipo Schema y es un middleware.

También puede crear su validación en el esquema o usar la validación integrada de Mongooses. Para evitar duplicados, recomendamos usar la propiedad única, ya que le dice a Mongoose que cada documento debe tener un valor único para la ruta dada.

Es una forma abreviada de crear un índice único de MongoDB en, en este caso, correo electrónico.

Si espera a que se cree el índice, puede usar el evento basado en promesas de Mongoose, Model.init(), como se muestra a continuación.

const User = mongoose.model('User', mongoose.Schema({
  email: {type: String, required: true, match: /.+\@.+\..+/, unique: true}
}));
await User.create([
  {email: 'gmail@google.com'}, {email: 'bill@microsoft.com'},
  {email: 'test@gmail.com'}
]);

await User.init();
try {
  await User.create({email: 'gmail@google.com'});
} catch (error) {
  error.message;  // 'E12000 duplicate key error...'
}

En este artículo, los índices únicos en MongoDB se analizan en detalle. Además, al final, la validación de correos electrónicos únicos se realiza en mangoose de MongoDB.

Artículo relacionado - MongoDB Index