sql >> Databáze >  >> NoSQL >> MongoDB

Denormalizace s Mongoose:Jak synchronizovat změny

Dobře, zatímco budu čekat na lepší odpověď, než je ta moje, pokusím se zveřejnit, co jsem dosud dělal.

Prostřední software před a po něm

První věc, kterou jsem zkusil, bylo použít pre/post middleware k synchronizaci dokumentů, které na sebe odkazují. (Například, pokud máte Author a Quote a Autor má pole typu:quotes: [{type: Schema.Types.ObjectId, ref:'Quotes'}] , pak vždy, když je smazána nabídka, musíte odstranit její _id z pole. Nebo pokud je autor odstraněn, můžete chtít odstranit všechny jeho citace).

Tento přístup má důležitouvýhodu :pokud definujete každé schéma v jeho vlastním souboru, můžete tam definovat middleware a mít to vše úhledně uspořádané . Kdykoli se podíváte na schéma, vpravo dole vidíte, co dělá, jak jeho změny ovlivňují jiné entity atd.:

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

Hlavní nevýhoda tyto háky se však nespouštějí, když zavoláte aktualizaci nebo jakoukoli funkci statické aktualizace/odebírání modelu . Spíše potřebujete načíst dokument a pak zavolat save() nebo remove() na nich.

Další menší nevýhodou je, že Quote nyní potřebuje vědět o každém, kdo na něj odkazuje, aby jej mohl aktualizovat, kdykoli je Quote aktualizován nebo odstraněn. Řekněme tedy, že Period obsahuje seznam citací a Author má také seznam uvozovek, společnost Quote o nich bude potřebovat vědět, aby je aktualizovala.

Důvodem je, že tyto funkce posílají atomické dotazy přímo do databáze. I když je to hezké, nenávidím nekonzistenci mezi použitím save() a Model.Update(...) . Možná někdo jiný nebo vy v budoucnu omylem použijete funkce statické aktualizace a váš middleware se nespustí, což vám způsobí bolesti hlavy, kterých se budete snažit zbavit.

Mechanismy událostí NodeJS

To, co v současné době dělám, není ve skutečnosti optimální, ale nabízí mi to dostatek výhod na to, abych převážil nevýhody (nebo tomu věřím, pokud by mi někdo dal nějakou zpětnou vazbu, bylo by to skvělé). Vytvořil jsem službu, která obklopuje model, řekněme AuthorService který rozšiřuje events.EventEmitter a je to funkce konstruktoru, která bude vypadat zhruba takto:

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()

Výhody:

  • Jakákoli zainteresovaná funkce se může zaregistrovat do servisních událostí a být informována. Tímto způsobem, například, když Quote je aktualizován, služba AuthorService jej může naslouchat a aktualizovat Authors podle toho. (Poznámka 1)
  • Cuote nemusí znát všechny dokumenty, které na něj odkazují, služba jednoduše spustí QuoteUpdated událost a všechny dokumenty, které potřebují k provedení operací, když k tomu dojde.

Poznámka 1:Pokud je tato služba používána vždy, když někdo potřebuje komunikovat s mangustou.

Nevýhody:

  • Přidán standardní kód, který přímo používá službu namísto mangusty.
  • Nyní není zcela zřejmé, jaké funkce se volají při spuštění události.
  • Oddělujete producenta a spotřebitele za cenu čitelnosti (protože stačí emit('EventName', args) , není hned zřejmé, které služby naslouchají této události)

Další nevýhodou je, že někdo může získat model ze služby a zavolat save() , ve kterém se události nebudou spouštět i když jsem si jistý, že by se to dalo řešit nějakým hybridem mezi těmito dvěma řešeními.

Jsem velmi otevřený návrhům v této oblasti (proto jsem na prvním místě položil tuto otázku).



  1. Mongoose agregátní vyhledávání - Jak filtrovat podle konkrétního ID

  2. Jak Redis dosahuje vysoké propustnosti a výkonu?

  3. Volání Mongoose do geoNear s body GeoJSON jako parametry dotazu nefungují

  4. MongoDB – Zvažte definování beanu typu 'org.springframework.data.mongodb.repository.query.MongoEntityInformation' ve vaší konfiguraci