mongoDB / mongoose: unique if not null

Eu queria saber se existe uma maneira de forçar uma input de coleção exclusiva, mas somente se a input não for nula . e Esquema de amostra:

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

’email’, neste caso, não é necessário, mas se ’email’ for salvo, quero ter certeza de que esta input é única (em um nível de database).

As inputs vazias parecem obter o valor ‘null’, portanto, todas as inputs sem e-mails falham com a opção ‘unique’ (se houver um usuário diferente sem e-mail).

No momento, estou resolvendo isso em um nível de aplicativo, mas adoraria salvar essa consulta do database.

THX

A partir do MongoDB v1.8 +, você pode obter o comportamento desejado de garantir valores exclusivos, mas permitindo vários documentos sem o campo, definindo a opção sparse como true ao definir o índice. Como em:

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

Ou no shell:

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

Observe que um índice único e esparso ainda não permite vários documentos com um campo de emailemail com valor null , apenas vários documentos sem um campo de emailemail .

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

tl; dr

Sim, isso pode ser feito.
Vários documentos com o campo definido como null ou não definido, enquanto impõe valores “reais” exclusivos.

requisitos :

  • MongoDB v3.2 +.
  • Quando você tem um valor real, ele deve ser de um tipo específico (por exemplo, sempre uma string).

Como? Vá para os detalhes da implementação abaixo.

versão mais longa

Para complementar a resposta de @ Nolan, começando com o MongoDB v3.2, você pode usar um índice exclusivo parcial com uma expressão de filtro.

A expressão de filtro parcial tem limitações. Só pode include o seguinte:

  • expressões de igualdade (ou seja, campo: valor ou usando o operador $eq ),
  • $exists: true expressão $exists: true
  • Expressões $gt , $gte , $lt , $lte ,
  • $type expressões,
  • $and operador apenas no nível superior

Isso significa que a expressão trivial {"yourField"{$ne: null}} não pode ser usada.

No entanto, supondo que seu campo sempre use o mesmo tipo , você pode usar uma expressão $type .

 { field: { $type:  |  } } 

implementação

mangusto

Você pode especificá-lo em um esquema de mangusto:

 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'}} } } }); 

ou diretamente adicioná-lo à coleção (que usa o driver node.js nativo):

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

motorista mongodb nativo

usando collection.createIndex

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

escudo mongodb

usando db.collection.createIndex :

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

Isso permitirá inserir vários registros com um email null ou sem um campo de email, mas não com a mesma sequência de email.

Apenas uma atualização rápida para quem está pesquisando esse tópico.

A resposta selecionada funcionará, mas você pode querer considerar o uso de índices parciais.

Alterado na versão 3.2: A partir do MongoDB 3.2, o MongoDB fornece a opção de criar índices parciais. Índices parciais oferecem um superconjunto da funcionalidade de índices esparsos. Se você estiver usando o MongoDB 3.2 ou posterior, os índices parciais devem ser preferidos em relação a índices esparsos.

Mais doco em índices parciais: https://docs.mongodb.com/manual/core/index-partial/

Na verdade, apenas o primeiro documento em que “email”, como campo não existe, será salvo com sucesso. As salvaguardas posteriores em que “email” não está presente falharão ao dar erro (consulte o fragment de código abaixo). Veja a documentação oficial do MongoDB com relação aos Índices Únicos e Chaves Ausentes aqui em 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 definição, o índice exclusivo só pode permitir que um valor seja armazenado apenas uma vez. Se você considerar nulo como um desses valores, ele só poderá ser inserido uma vez! Você está correto em sua abordagem, garantindo e validando-o no nível do aplicativo. É assim que isso pode ser feito.

Você também pode gostar de ler este http://www.mongodb.org/display/DOCS/Querying+and+nulls