mongoDB / mongoose: único si no nulo

Me preguntaba si hay forma de forzar una entrada de colección única, pero solo si la entrada no es nula . e esquema de muestra:

var UsersSchema = new Schema({ name : {type: String, trim: true, index: true, required: true}, email : {type: String, trim: true, index: true, unique: true} }); 

‘correo electrónico’ en este caso no es necesario, pero si se guarda ‘correo electrónico’, quiero asegurarme de que esta entrada sea única (a nivel de base de datos).

Las entradas vacías parecen obtener el valor “nulo”, por lo que cada entrada sin correo electrónico se bloquea con la opción “única” (si hay un usuario diferente sin correo electrónico).

En este momento estoy resolviéndolo en un nivel de aplicación, pero me encantaría guardar esa consulta db.

Gracias

A partir de MongoDB v1.8 + puede obtener el comportamiento deseado de garantizar valores únicos pero permitiendo múltiples documentos sin el campo estableciendo la opción sparse en verdadero al definir el índice. Como en:

 email : {type: String, trim: true, index: true, unique: true, sparse: true} 

O en el caparazón:

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

Tenga en cuenta que un índice disperso y único aún no permite varios documentos con un campo de email con un valor null , solo varios documentos sin un campo de email .

Ver http://docs.mongodb.org/manual/core/index-sparse/

tl; dr

Sí, se puede hacer.
Varios documentos con el campo establecido como null o no definido, mientras se aplican valores “reales” únicos.

requisitos :

  • MongoDB v3.2 +.
  • Cuando su campo ר tiene un valor real, debe ser de un tipo específico (por ejemplo, siempre una cadena).

¿Cómo? Vaya a los detalles de implementación a continuación.

versión más larga

Para complementar la respuesta de @Nolan, comenzando con MongoDB v3.2 puede usar un índice único parcial con una expresión de filtro.

La expresión de filtro parcial tiene limitaciones. Solo puede incluir lo siguiente:

  • expresiones de igualdad (es decir, campo: valor o usando el operador $eq ),
  • $exists: true expresión $exists: true ,
  • $gt , $gte , $lt , $lte expresiones,
  • $type expresiones,
  • $and operador solo en el nivel superior

Esto significa que no se puede usar la expresión trivial {"yourField"{$ne: null}} .

Sin embargo, suponiendo que su campo siempre usa el mismo tipo , puede usar una expresión $type .

 { field: { $type:  |  } } 

implementación

mongoose

Puedes especificarlo en un esquema de mongoose:

 const UsersSchema = new Schema({ name: {type: String, trim: true, index: true, required: true}, email: { type: String, trim: true, index: { unique: true, partialFilterExpression: {email: {$type: 'string'}} } } }); 

o directamente agregarlo a la colección (que usa el controlador node.js nativo):

 User.collection.createIndex("email", { unique: true, partialFilterExpression: { "email": { $type: "string" } } }); 

conductor mongodb nativo

utilizando collection.createIndex

 db.collection('users').createIndex({ "email": 1 }, { unique: true, partialFilterExpression: { "email": { $type: "string" } } }, function (err, results) { // ... } ); 

concha mongodb

utilizando db.collection.createIndex :

 db.users.createIndex({ "email": 1 }, { unique: true, partialFilterExpression: { "email": {$type: "string"} } }) 

Esto permitirá insertar múltiples registros con un correo electrónico null , o sin un campo de correo electrónico en absoluto, pero no con la misma cadena de correo electrónico.

Solo una actualización rápida para aquellos que investigan este tema.

La respuesta seleccionada funcionará, pero es posible que desee considerar el uso de índices parciales en su lugar.

Modificado en la versión 3.2: a partir de MongoDB 3.2, MongoDB ofrece la opción de crear índices parciales. Los índices parciales ofrecen un superconjunto de la funcionalidad de índices dispersos. Si está utilizando MongoDB 3.2 o posterior, los índices parciales deberían preferirse sobre los índices dispersos.

Más doco en índices parciales: https://docs.mongodb.com/manual/core/index-partial/

En realidad, solo el primer documento donde “correo electrónico” como campo no existe se guardará con éxito. Los guardados posteriores en los que “correo electrónico” no está presente fallarán al dar error (vea el fragmento de código a continuación). Por la razón, consulte la documentación oficial de MongoDB con respecto a Índices únicos y Llaves perdidas aquí en http://www.mongodb.org/display/DOCS/Indexes#Indexes-UniqueIndexes .

  // NOTE: Code to executed in mongo console. db.things.ensureIndex({firstname: 1}, {unique: true}); db.things.save({lastname: "Smith"}); // Next operation will fail because of the unique index on firstname. db.things.save({lastname: "Jones"}); 

Por definición, un índice único solo puede permitir que un valor se almacene solo una vez. ¡Si considera nulo como uno de esos valores, solo se puede insertar una vez! Tiene razón en su enfoque al garantizarlo y validarlo a nivel de aplicación. Así es como se puede hacer.

También puede leer este http://www.mongodb.org/display/DOCS/Querying+and+nulls