Oke, sembari menunggu jawaban yang lebih baik dari jawaban saya sendiri, saya akan mencoba memposting apa yang telah saya lakukan selama ini.
Perangkat Tengah Sebelum/Pasca
Hal pertama yang saya coba adalah menggunakan pre/post middlewares
untuk menyinkronkan dokumen yang direferensikan satu sama lain. (Misalnya, jika Anda memiliki Author
dan Quote
, dan Penulis memiliki larik dengan tipe:quotes: [{type: Schema.Types.ObjectId, ref:'Quotes'}]
, maka setiap kali Kutipan dihapus, Anda harus menghapus _id
.nya dari larik. Atau jika Penulis dihapus, Anda mungkin ingin semua kutipannya dihapus).
Pendekatan ini memiliki keuntungan yang penting :jika Anda mendefinisikan setiap Skema dalam filenya sendiri, Anda dapat menentukan middleware di sana dan membuat semuanya teratur dengan rapi . Setiap kali Anda melihat skema, tepat di bawah Anda dapat melihat apa yang dilakukannya, bagaimana perubahannya memengaruhi entitas lain, dll:
var Quote = new Schema({
//fields in schema
})
//its quite clear what happens when you remove an entity
Quote.pre('remove', function(next) {
Author.update(
//remove quote from Author quotes array.
)
})
Kerugian utama namun kait ini tidak dijalankan saat Anda memanggil pembaruan atau fungsi pembaruan/penghapusan statis Model apa pun
. Sebaliknya Anda perlu mengambil dokumen dan kemudian memanggil save()
atau remove()
pada mereka.
Kerugian lain yang lebih kecil adalah Quote sekarang perlu mengetahui siapa saja yang mereferensikannya, sehingga dapat memperbaruinya setiap kali Quote diperbarui atau dihapus. Jadi katakanlah sebuah Period
memiliki daftar kutipan, dan Author
memiliki daftar kutipan juga, Kutipan perlu mengetahui tentang keduanya untuk memperbaruinya.
Alasan untuk ini adalah bahwa fungsi-fungsi ini mengirim kueri atom ke database secara langsung. Meskipun ini bagus, saya benci inkonsistensi antara menggunakan save()
dan Model.Update(...)
. Mungkin orang lain atau Anda di masa mendatang secara tidak sengaja menggunakan fungsi pembaruan statis dan middleware Anda tidak terpicu, membuat Anda sakit kepala dan sulit untuk dihilangkan.
Mekanisme Peristiwa NodeJS
Apa yang saya lakukan saat ini tidak benar-benar optimal tetapi menawarkan saya manfaat yang cukup untuk benar-benar melebihi kontra (Atau jadi saya percaya, jika ada yang peduli untuk memberi saya umpan balik itu bagus). Saya membuat layanan yang membungkus model, katakanlah AuthorService
yang memperluas events.EventEmitter
dan merupakan fungsi Konstruktor yang kira-kira akan terlihat seperti ini:
function AuthorService() {
var self = this
this.create = function() {...}
this.update = function() {
...
self.emit('AuthorUpdated, before, after)
...
}
}
util.inherits(AuthorService, events.EventEmitter)
module.exports = new AuthorService()
Kelebihannya:
- Setiap fungsi yang tertarik dapat mendaftar ke Acara Layanan dan diberi tahu. Dengan cara itu, misalnya, ketika
Quote
diperbarui, AuthorService dapat mendengarkannya dan memperbaruiAuthors
demikian. (Catatan 1) - Quote tidak perlu mengetahui semua dokumen yang merujuknya, Layanan hanya memicu
QuoteUpdated
acara dan semua dokumen yang perlu melakukan operasi saat ini terjadi akan melakukannya.
Catatan 1:Selama layanan ini digunakan kapan pun ada orang yang perlu berinteraksi dengan luwak.
Kekurangannya:
- Menambahkan kode boilerplate, menggunakan layanan alih-alih luwak secara langsung.
- Sekarang tidak begitu jelas fungsi apa yang dipanggil saat Anda memicu acara.
- Anda memisahkan produsen dan konsumen dengan biaya keterbacaan (karena Anda hanya
emit('EventName', args)
, tidak jelas Layanan mana yang mendengarkan acara ini)
Kerugian lainnya adalah seseorang dapat mengambil Model dari Layanan dan memanggil save()
, di mana peristiwa tidak akan dipicu meskipun saya yakin ini dapat diatasi dengan semacam hibrida antara dua solusi ini.
Saya sangat terbuka untuk saran di bidang ini (itulah sebabnya saya memposting pertanyaan ini sejak awal).