L'index Mongoose Unique ne fonctionne pas!


95

J'essaie de laisser MongoDB détecter une valeur en double en fonction de son index. Je pense que cela est possible dans MongoDB, mais à travers le wrapper Mongoose, les choses semblent être cassées. Donc pour quelque chose comme ça:

User = new Schema ({
  email: {type: String, index: {unique: true, dropDups: true}}
})

Je peux enregistrer 2 utilisateurs avec le même email. Zut.

Le même problème a été exprimé ici: https://github.com/LearnBoost/mongoose/issues/56 , mais ce fil est ancien et ne mène à nulle part.

Pour l'instant, je passe manuellement un appel à la base de données pour trouver l'utilisateur. Cet appel n'est pas cher puisque «l'email» est indexé. Mais ce serait toujours bien de le laisser géré de manière native.

Quelqu'un at-il une solution à cela?


1
Mauvaise nouvelle, c'est toujours un problème avec mongod v2.4.3, mangouste v3.6.20
Damphat

Unique semble fonctionner sur l'un de mes hôtes, mais ne parvient pas à appliquer les uniques en utilisant exactement le même code de nœud / mangouste sur un hôte différent. L'hôte qui fonctionne correctement exécute un seul mongod 3.4.10, celui qui ne fonctionne pas - exécute un jeu de répliques avec mongod 3.2.17.Sur les deux hôtes, je crée une collection à partir de zéro, donc les dups existants ne sont pas un problème. J'ai essayé la plupart des solutions sur cette page et celle qui a fonctionné était le validateur unique de mangouste de @Isaac Pak.
Maksym

Réponses:


95

Oups! Il vous suffit de redémarrer mongo.


4
J'ai le même problème, mais je ne peux pas trouver comment redémarrer mongo sur OSX. Lorsque je tue le processus, il réapparaît automatiquement et l'index unique ne fonctionne toujours pas ... des idées?
ragulka

7
que voulez-vous dire "oups vous avez juste à redémarrer mongo"?! dites-vous qu'il est impossible d'ajouter un index sans faire tomber la base de données?
andrewrk

7
Ce n'est pas vrai. Vous n'avez pas besoin de redémarrer mongo pour ajouter un index.
JohnnyHK

1
pour la chose unique .. J'ai dû redémarrer mongo .. et cela a fonctionné .. Merci!
Muhammad Ahsan Ayaz

2
J'ai essayé de redémarrer. Réindexation également. J'ai dû supprimer la base de données pour résoudre ce problème. Je suppose que le problème est que les doublons existaient déjà avant d'ajouter l'index, donc dans une base de données de production, j'aurais besoin de supprimer les doublons, puis de redémarrer?
isimmons

40

Oups! Il vous suffit de redémarrer mongo.

Et ré-indexez aussi, avec:

mongo <db-name>
> db.<collection-name>.reIndex()

Lors des tests, comme je n'ai pas de données importantes, vous pouvez également faire:

mongo <db-name>
> db.dropDatabase()

16
db.dropDatabase () efface votre base de données!
Isaac Pak

28

J'ai rencontré le même problème: j'ai ajouté la contrainte unique pour le emailchamp à notre UserSchemaaprès avoir déjà ajouté des utilisateurs à la base de données, et j'étais toujours en mesure d'enregistrer des utilisateurs avec des e-mails dupliqués. J'ai résolu ce problème en procédant comme suit:

1) Supprimez tous les documents de la collection des utilisateurs.

2) Depuis le shell mongo, exécutez la commande: db.users.createIndex({email: 1}, {unique: true})

En ce qui concerne l'étape 1, notez que dans la documentation de Mongo:

MongoDB ne peut pas créer un index unique sur le (s) champ (s) d'index spécifié (s) si la collection contient déjà des données qui violeraient la contrainte d'unicité de l'index.

https://docs.mongodb.com/manual/core/index-unique/


11

Ce comportement se produit également si vous avez laissé des doublons dans Mongo. Mongoose essaiera de les créer dans Mongo au démarrage de votre application.

Pour éviter cela, vous pouvez gérer cette erreur de cette façon:

yourModel.on('index', function(err) {
  if (err?) {
    console.error err
  }
);

10

Ok, j'ai pu résoudre cela à partir du mongoshell en ajoutant l'index sur le terrain et en définissant la propriété unique:

db.<collectionName>.ensureIndex({fieldName: 1}, {unique: true});

Shell devrait répondre de cette manière:

{
    "createdCollectionAutomatically" : false,
    "numIndexesBefore" : 1,
    "numIndexesAfter" : 2,
    "ok" : 1
}

Maintenant, pour tester rapidement depuis le mongoshell:

var doc = {fieldName: 'abc'};
db.<collectionName>.insert(doc)

Doit donner: WriteResult ({"nInserted": 1})

Mais en répétant à nouveau:

db.<collectionName>.insert(doc)

Va donner:

WriteResult({
    "nInserted" : 0,
    "writeError" : {
        "code" : 11000,
        "errmsg" : "insertDocument :: caused by :: 11000 E11000 duplicate key error index: fuelConsumption.users.$email_1  dup key: { : \"martyna@martycud.com\" }"
    }
})

10

J'ai fait quelque chose comme ça:

const mongoose = require('mongoose');
const Schema = mongoose.Schema;

const FooSchema = new Schema({
   name: { type: String, required: true, index: true, unique: true }
});

const Foo = mongoose.model('Foo', FooSchema);

Foo.createIndexes();

module.exports = Foo

J'ai ajouté la Foo.createIndexes()ligne bc J'obtenais l'avertissement d'obsolescence suivant lorsque le code était en cours d'exécution:

(node:21553) DeprecationWarning: collection.ensureIndex is deprecated. Use createIndexes instead.

Je ne sais pas si Foo.createIndexes()c'est asynchrone, mais les choses AFAIK semblent bien fonctionner


La seule réponse à la question qui aborde le problème plutôt que de tourner autour de lui.
Saksham Gupta

Cette réponse m'a aidé. Tout ce qui me manquait, c'était la index: truecréation de mon index unique.
elcid le


5

Mongoose est un peu lâche lors de l'application d'index uniques au niveau de l'application; par conséquent, il est préférable d'appliquer vos index uniques à partir de la base de données elle-même à l'aide de mongo cli ou de dire explicitement à mongoose que vous êtes sérieux au sujet de l' uniqueindex en écrivant la ligne de code suivante juste après votre UserSchema:

UserSchema.index({ username: 1, email: 1 }, { unique: true});

Cela appliquera l'index unique sur les champs usernameet emaildans votre UserSchema. À votre santé.


5
Un peu tard à la fête, mais à quoi bon un ORM qui est "un peu lâche lors de l'application d'indices uniques"
Imre_G

Ce qui est bon, ce sont des commentaires dénigrants qui n'aident en rien. Cette solution est solide et prête pour la production.
Isaac Pak

4

Mongoose échouera silencieusement à ajouter un index unique lorsque:

  1. La collection a déjà un index du même nom
  2. La collection contient déjà des documents avec des doublons du champ indexé

Dans le premier cas, répertoriez les index avec db.collection.getIndexes()et supprimez l'ancien index avec db.collection.dropIndex("index_name"). Lorsque vous redémarrez l'application Mongoose, elle doit ajouter correctement le nouvel index.

Dans le second cas, vous devez supprimer les doublons avant de redémarrer l'application Mongoose.


3

mongoose-unique-validator

Comment utiliser ce plugin:

1) npm install --save mongoose-unique-validator

2) dans votre schéma, suivez ce guide:

// declare this at the top
var mongoose = require('mongoose');
var uniqueValidator = require('mongoose-unique-validator');

// exampleSchema = mongoose.Schema({}) etc...

exampleSchema.plugin(uniqueValidator);

// module.exports = mongoose.model(...) etc....

3) méthodes de mangouste

Lorsque vous utilisez des méthodes comme findOneAndUpdatevous devrez passer cet objet de configuration:

{ runValidators: true, context: 'query' }

ie. User.findOneAndUpdate(
      { email: 'old-email@example.com' },
      { email: 'new-email@example.com' },
      { runValidators: true, context: 'query' },
      function(err) {
        // ...
    }

4) options supplémentaires

  1. insensible à la casse

    utilisez l'option uniqueCaseInsensitive dans votre schéma

    ie. email: { type: String, index: true, unique: true, required: true, uniqueCaseInsensitive: true }

  2. messages d'erreur personnalisés

    ie. exampleSchema.plugin(uniqueValidator, { message: 'Error, expected {PATH} to be unique.' });

Vous pouvez maintenant ajouter / supprimer la propriété unique à vos schémas sans vous soucier du redémarrage de mongo, de la suppression de bases de données ou de la création d'index.

Mises en garde (tirées de la documentation):

Étant donné que nous nous appuyons sur des opérations asynchrones pour vérifier si un document existe dans la base de données, il est possible que deux requêtes s'exécutent en même temps, toutes les deux récupèrent 0, puis les deux s'insèrent dans MongoDB.

En dehors du verrouillage automatique de la collection ou du forçage d'une seule connexion, il n'y a pas de vraie solution.

Pour la plupart de nos utilisateurs, ce ne sera pas un problème, mais c'est un cas extrême dont il faut être conscient.


2

Réponse la plus récente: il n'est pas du tout nécessaire de redémarrer mongodb, si colleciton a déjà des index de même nom, mongoose ne recréera pas vos index à nouveau, alors supprimez d'abord les index existants de colleciton, et maintenant, lorsque vous exécutez mangouste, il créera un nouvel index , le processus ci-dessus a résolu mon problème.


1

Vous pouvez également résoudre ce problème en supprimant l'index;

supposons que vous souhaitiez supprimer l'index unique de la collection userset du champ username, tapez ceci:

db.users.dropIndex('username_1');


1

Si la table / collection est vide, créez un index unique pour le champ:

db.<collection_name>.createIndex({'field':1}, {unique: true})

Si la table / collection n'est pas vide, supprimez la collection et créez un index:

db.<collection_name>.drop()
db.<collection_name>.createIndex({'field':1}, {unique: true})

Maintenant, redémarrez mongoDB.


1

vérifiez que autoIndex dans le schéma est true, il peut être défini sur false (true par défaut) lorsque vous utilisez les options mongoose.connect


1

J'ai été confronté au même problème pendant un certain temps et j'ai fait beaucoup de recherches et la solution pour moi était la createIndexes()fonction.

Je souhaite que cela aide.

donc le code sera comme ça.

User = new Schema ({
   email: {type: String, unique: true}
});
User.createIndexes();

0

Si vous utilisez l'option autoIndex: falsedans la méthode de connexion comme ceci:

mongoose.connect(CONNECTION_STRING, { autoIndex: false });

Essayez de supprimer cela. Si cela ne fonctionne pas, essayez de redémarrer mongodb autant que suggéré dans ce fil.


0

Vous pouvez définir votre schéma comme

User = new Schema ({
  email: {
      type: String,
      unique: true
  }
})

Mais peut-être que cela ne fonctionnera pas quand il y a déjà un document et après cela, vous avez changé le schéma de l'utilisateur. Vous pouvez créer un index par e-mail pour cette collection User si vous ne souhaitez pas supprimer la collection. En utilisant cette commande, vous pouvez créer un index sur l'e-mail.

db.User.createIndex({email:1},{unique: true})

Ou vous pouvez simplement supprimer la collection et ajouter à nouveau l'utilisateur.
Pour supprimer la collection, vous pouvez saisir ceci:

db.User.drop()

0

Lorsque j'ai rencontré ce problème, j'ai essayé de supprimer la base de données, de redémarrer le serveur (nodemon) plusieurs fois et aucune des astuces n'a fonctionné du tout. J'ai trouvé le travail suivant, via Robo 3T:

  1. Dans le Robo 3T, double-cliquez sur la base de données pour ouvrir les collections
  2. Ouvrez les collections pour révéler la collection en question. Assurez-vous que vos collections sont vides, pour commencer
  3. Cliquez avec le bouton droit sur le dossier Indexes. Par défaut, vous verrez le _id_par défaut. Maintenant, choisissez Ajouter un index
  4. Choisissez un nom, par exemple emailpour le champ e-mail, par exemple
  5. Fournissez des clés au format JSON. Par exemple

    {
       "email": 1
    }
    
  6. Cliquez sur la case à cocher Unique

  7. sauvegarder

Cela garantira qu'aucun e-mail en double n'est enregistré dans MongoDB.


quelle est la signification de 1 ici dans l'objet {"email": 1}?
siluveru kiran kumar le

0

Assurez-vous que votre collection n'a pas de redondance du champ sur lequel vous venez de mettre l'index unique.

Ensuite, redémarrez simplement votre application (mangouste). Il suffit d'ajouter un index en silence.


0

Suppression de tous les documents de la collection:

db.users.remove({})

Et un redémarrage, comme d'autres l'ont mentionné, a fonctionné pour moi


0

Si votre MongoDB fonctionne en tant que service (un moyen simple de le trouver est si vous n'avez pas besoin de vous connecter à la base de données sans démarrer le fichier mongod.exe via un terminal), après avoir effectué les modifications, vous devrez peut-être redémarrer le service et / ou supprimez complètement votre base de données.

C'est assez étrange car pour certains utilisateurs, le simple fait de déposer une seule collection fonctionnait. Certains d'entre eux avaient juste besoin de supprimer la base de données. Mais cela n'a pas fonctionné pour moi. J'ai abandonné la base de données, puis redémarré le service MongoDB Server.

Pour redémarrer un service de recherche Services sur la barre de recherche Windows puis trouver le service MongoDB, double-cliquez pour ouvrir puis arrêter et redémarrer le service.

Si les autres méthodes n'ont pas fonctionné pour vous, je pense que cela fera l'affaire.


0

Dans mon cas, la mangouste était dépassée. Je l'ai vérifié en exécutant npm obsolète sur CMD. et mis à jour «mangouste».

Veuillez dire si cela a fonctionné pour vous aussi.


Quelle version utilisiez-vous?
Baboo_

0

Lorsque vous connectez votre base de données à l'application ajoutez cette option: "audoIndex: true" par exemple dans mon code j'ai fait ceci:

const options = {
// your options go here
...
// this code is the solution
audoIndex: true
}
mongoose.connect(DB_URI, options);

J'ai également abandonné la collection avec laquelle j'ai un problème et je l'ai recréée pour m'assurer qu'elle fonctionnera. J'ai trouvé cette solution sur: https://dev.to/emmysteven/solved-mongoose-unique-index-not-working-45d5 J'ai aussi essayé des solutions comme "redémarrer MongoDB" mais cela n'a pas fonctionné pour moi.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.