En résumé
Oui, il est possible d'avoir plusieurs documents dont le champ est défini comme suit null
ou non définies, tout en imposant des valeurs "réelles" uniques.
exigences :
- MongoDB v3.2+.
- Connaître à l'avance le(s) type(s) de valeur concrète (par exemple, toujours une
string
o object
quand ce n'est pas null
).
Si vous n'êtes pas intéressé par les détails, n'hésitez pas à passer à l'étape suivante. 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 "filtre partiel" a des limites. Elle ne peut inclure que les éléments suivants :
- des expressions d'égalité (c'est-à-dire champ : valeur ou utilisation de la fonction
$eq
opérateur),
-
$exists: true
expression,
-
$gt
, $gte
, $lt
, $lte
expressions,
-
$type
expressions,
-
$and
uniquement au niveau supérieur
Cela signifie que l'expression triviale {"yourField"{$ne: null}}
ne peut être utilisé.
Cependant, en supposant que votre domaine utilise toujours le même type vous pouvez utiliser un $type
expression .
{ field: { $type: <BSON type number> | <String alias> } }
MongoDB v3.6 a ajouté la possibilité de spécifier plusieurs types possibles, qui peuvent être transmis sous forme de tableau :
{ field: { $type: [ <BSON type1> , <BSON type2>, ... ] } }
ce qui signifie qu'il permet à la valeur d'être de n'importe quel type parmi un certain nombre de types multiples lorsqu'elle n'est pas null
.
Par conséquent, si nous voulons permettre à la email
dans l'exemple ci-dessous pour accepter soit string
ou, disons, binary data
valeurs, une $type
l'expression serait :
{email: {$type: ["string", "binData"]}}
mise en œuvre
mangouste
Vous pouvez le spécifier dans un schéma 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"}}
}
}
});
ou l'ajouter 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) {
// ...
}
);
shell 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
email, ou sans champ email du tout, mais pas avec la même chaîne email.