tl; dr
Oui, il est possible d'avoir plusieurs documents avec un champ défini sur null
ou 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
string
ou object
quand pas null
).
Si vous n'êtes pas intéressé par les détails, n'hésitez pas à passer à la implementation
section.
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'
$eq
opérateur),
$exists: true
expression,
$gt
, $gte
, $lt
, $lte
Expressions,
$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 $type
expression .
{ 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 email
champ de l'exemple ci-dessous à accepter l'une string
ou, par exemple, des binary data
valeurs, une $type
expression 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 null
e - mail, ou sans champ e-mail du tout, mais pas avec la même chaîne d'e-mail.