MongoDB
 sql >> Base de données >  >> NoSQL >> MongoDB

Erreur de clé en double Mongoose avec upsert

Un upsert qui se traduit par une insertion de document n'est pas une opération entièrement atomique. Considérez l'upsert comme effectuant les étapes discrètes suivantes :

  1. Requête pour le document identifié à mettre à jour.
  2. Si le document existe, mettre à jour le document existant de manière atomique.
  3. Sinon (le document n'existe pas), insérez de manière atomique un nouveau document qui intègre les champs de requête et la mise à jour.

Ainsi, les étapes 2 et 3 sont chacune atomiques, mais un autre upsert peut se produire après l'étape 1. Votre code doit donc vérifier l'erreur de clé en double, puis réessayer l'upsert si cela se produit. À ce stade, vous connaissez le document avec ce _id existe donc il réussira toujours.

Par exemple :

var minute = utils.minute();
Monitor.update({ _id: minute }, { $inc: update }, { upsert: true }, function(err) {
    if (err) {
        if (err.code === 11000) {
            // Another upsert occurred during the upsert, try again. You could omit the
            // upsert option here if you don't ever delete docs while this is running.
            Monitor.update({ _id: minute }, { $inc: update }, { upsert: true },
                function(err) {
                    if (err) {
                        console.trace(err);
                    }
                });
        }
        else {
            console.trace(err);
        }
    }
});

Voir ici pour la documentation associée.

Vous vous demandez peut-être encore pourquoi cela peut arriver si l'insertion est atomique, mais cela signifie qu'aucune mise à jour ne se produira sur le document inséré jusqu'à ce qu'il soit complètement écrit, pas qu'aucune autre insertion d'un document avec le même _id peut se produire.

De plus, vous n'avez pas besoin de créer manuellement un index sur _id car toutes les collections MongoDB ont un index unique sur _id indépendamment. Vous pouvez donc supprimer cette ligne :

monitorSchema.index({_id: -1}); // Not needed