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

Dénormalisation avec Mongoose :comment synchroniser les modifications

Ok, en attendant une meilleure réponse que la mienne, je vais essayer de poster ce que j'ai fait jusqu'à présent.

Pré/Post Middleware

La première chose que j'ai essayée a été d'utiliser les pre/post middlewares pour synchroniser des documents qui se référaient les uns aux autres. (Par exemple, si vous avez Author et Quote , et un auteur a un tableau du type :quotes: [{type: Schema.Types.ObjectId, ref:'Quotes'}] , alors chaque fois qu'un devis est supprimé, vous devez supprimer son _id du tableau. Ou si l'auteur est supprimé, vous souhaiterez peut-être supprimer toutes ses citations).

Cette approche présente un avantage important  :si vous définissez chaque schéma dans son propre fichier, vous pouvez y définir le middleware et tout organiser de façon soigneusement . Chaque fois que vous regardez le schéma, juste en dessous, vous pouvez voir ce qu'il fait, comment ses modifications affectent d'autres entités, etc :

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

Le principal inconvénient cependant, ces crochets ne sont pas exécutés lorsque vous appelez la mise à jour ou toute fonction de mise à jour/suppression statique du modèle . Vous devez plutôt récupérer le document, puis appeler save() ou remove() sur eux.

Un autre petit inconvénient est que Quote doit désormais être au courant de toute personne qui y fait référence, afin qu'il puisse les mettre à jour chaque fois qu'un devis est mis à jour ou supprimé. Disons donc qu'une Period a une liste de citations et Author a également une liste de citations, Quote devra connaître ces deux-là pour les mettre à jour.

La raison en est que ces fonctions envoient directement des requêtes atomiques à la base de données. Bien que ce soit bien, je déteste l'incohérence entre l'utilisation de save() et Model.Update(...) . Peut-être que quelqu'un d'autre ou vous-même utiliserez accidentellement les fonctions de mise à jour statique et votre middleware ne se déclenchera pas, ce qui vous causera des maux de tête dont vous aurez du mal à vous débarrasser.

Mécanismes d'événements NodeJS

Ce que je fais actuellement n'est pas vraiment optimal, mais il m'offre suffisamment d'avantages pour dépasser les inconvénients (ou alors je crois, si quelqu'un veut bien me faire part de ses commentaires, ce serait formidable). J'ai créé un service qui s'articule autour d'un modèle, disons AuthorService qui étend events.EventEmitter et est une fonction Constructeur qui ressemblera à peu près à ceci :

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

Les avantages :

  • Toute fonction intéressée peut s'inscrire aux événements du Service et être notifiée. Ainsi, par exemple, lorsqu'un Quote isupdated, l'AuthorService peut l'écouter et mettre à jour les Authors en conséquence. (Remarque 1)
  • Quote n'a pas besoin d'être au courant de tous les documents qui y font référence, le service déclenche simplement le QuoteUpdated événement et tous les documents qui doivent effectuer des opérations lorsque cela se produit le feront.

Remarque 1 :Tant que ce service est utilisé chaque fois que quelqu'un a besoin d'interagir avec la mangouste.

Les inconvénients :

  • Ajout d'un code passe-partout, utilisant directement un service au lieu de mongoose.
  • Maintenant, il n'est pas exactement évident quelles fonctions sont appelées lorsque vous déclenchez l'événement.
  • Vous découplez le producteur et le consommateur au détriment de la lisibilité (puisque vous ne faites que emit('EventName', args) , il n'est pas immédiatement évident quels services écoutent cet événement)

Un autre inconvénient est que quelqu'un peut récupérer un modèle à partir du service et appeler save() , dans lequel les événements ne seront pas déclenchés même si je suis sûr que cela pourrait être résolu avec une sorte d'hybride entre ces deux solutions.

Je suis très ouvert aux suggestions dans ce domaine (c'est pourquoi j'ai posté cette question en premier lieu).