Sebuah upsert yang menghasilkan penyisipan dokumen bukanlah operasi atom sepenuhnya. Pikirkan upsert sebagai melakukan langkah-langkah diskrit berikut:
- Kueri untuk dokumen yang diidentifikasi untuk di-upser.
- Jika dokumen ada, perbarui dokumen yang ada secara atomik.
- Selain itu (dokumen tidak ada), masukkan dokumen baru secara atomik yang menggabungkan bidang kueri dan pembaruan.
Jadi langkah 2 dan 3 masing-masing atom, tetapi upsert lain dapat terjadi setelah langkah 1 sehingga kode Anda perlu memeriksa kesalahan kunci duplikat dan kemudian coba lagi upsert jika itu terjadi. Pada saat itu Anda tahu dokumen dengan _id
itu ada sehingga akan selalu berhasil.
Misalnya:
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);
}
}
});
Lihat di sini untuk dokumentasi terkait.
Anda mungkin masih bertanya-tanya mengapa ini bisa terjadi jika sisipan bersifat atomik, tetapi artinya tidak ada pembaruan yang akan terjadi pada dokumen yang disisipkan hingga dokumen tersebut benar-benar ditulis, bukan berarti tidak ada sisipan dokumen lain dengan _id
dapat terjadi.
Selain itu, Anda tidak perlu membuat indeks secara manual di _id
karena semua koleksi MongoDB memiliki indeks unik di _id
tanpa memedulikan. Jadi Anda dapat menghapus baris ini:
monitorSchema.index({_id: -1}); // Not needed