MongoDB
 sql >> Database >  >> NoSQL >> MongoDB

Errore chiave duplicata Mongoose con upsert

Un upsert che risulta in un inserimento di un documento non è un'operazione completamente atomica. Pensa all'upsert come all'esecuzione dei seguenti passaggi discreti:

  1. Richiesta di inserimento del documento identificato.
  2. Se il documento esiste, aggiorna atomicamente il documento esistente.
  3. Altrimenti (il documento non esiste), inserire atomicamente un nuovo documento che incorpori i campi di query e l'aggiornamento.

Quindi i passaggi 2 e 3 sono ciascuno atomico, ma dopo il passaggio 1 potrebbe verificarsi un altro upsert, quindi il codice deve verificare l'errore della chiave duplicata e quindi riprovare l'upsert se ciò si verifica. A quel punto conosci il documento con quel _id esiste quindi avrà sempre successo.

Ad esempio:

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);
        }
    }
});

Vedi qui per la relativa documentazione.

Potresti ancora chiederti perché questo può accadere se l'inserto è atomico, ma ciò significa che non si verificheranno aggiornamenti sul documento inserito fino a quando non sarà completamente scritto, non che nessun altro inserto di un documento con lo stesso _id può verificarsi.

Inoltre, non è necessario creare manualmente un indice su _id poiché tutte le raccolte MongoDB hanno un indice univoco su _id indipendentemente. Quindi puoi rimuovere questa riga:

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