tl; dr
Oui, il est possible d'avoir plusieurs documents avec un champ défini sur nullou non défini, tout en appliquant des valeurs «réelles» uniques.
exigences :
- MongoDB v3.2 +.
- Connaître vos types de valeurs concrètes à l'avance (par exemple, toujours a
stringou objectquand pas null).
Si vous n'êtes pas intéressé par les détails, n'hésitez pas à passer à la implementationsection.
version plus longue
Pour compléter la réponse de @ Nolan, à partir de MongoDB v3.2, vous pouvez utiliser un index unique partiel avec une expression de filtre.
L'expression de filtre partiel a des limites. Il ne peut inclure que les éléments suivants:
- expressions d'égalité (ie champ: valeur ou en utilisant l'
$eqopérateur),
$exists: true expression,
$gt, $gte, $lt, $lteExpressions,
$type expressions,
$and opérateur au niveau supérieur uniquement
Cela signifie que l'expression triviale {"yourField"{$ne: null}}ne peut pas être utilisée.
Cependant, en supposant que votre champ utilise toujours le même type , vous pouvez utiliser une $typeexpression .
{ field: { $type: <BSON type number> | <String alias> } }
MongoDB v3.6 a ajouté la prise en charge de la spécification de plusieurs types possibles, qui peuvent être passés sous forme de tableau:
{ field: { $type: [ <BSON type1> , <BSON type2>, ... ] } }
ce qui signifie qu'il permet à la valeur d'être de l'un de plusieurs types multiples si ce n'est pas le cas null.
Par conséquent, si nous voulons autoriser le emailchamp de l'exemple ci-dessous à accepter l'une stringou, par exemple, des binary datavaleurs, une $typeexpression appropriée serait:
{email: {$type: ["string", "binData"]}}
la mise en oeuvre
mangouste
Vous pouvez le spécifier dans un schéma mangouste:
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 ajoutez-le directement à la collection (qui utilise le pilote node.js natif):
User.collection.createIndex("email", {
unique: true,
partialFilterExpression: {
"email": {
$type: "string"
}
}
});
pilote natif mongodb
en utilisant collection.createIndex
db.collection('users').createIndex({
"email": 1
}, {
unique: true,
partialFilterExpression: {
"email": {
$type: "string"
}
}
},
function (err, results) {
// ...
}
);
coque mongodb
en utilisant db.collection.createIndex:
db.users.createIndex({
"email": 1
}, {
unique: true,
partialFilterExpression: {
"email": {$type: "string"}
}
})
Cela permettra d'insérer plusieurs enregistrements avec un nulle - mail, ou sans champ e-mail du tout, mais pas avec la même chaîne d'e-mail.