sql >> Base de Datos >  >> NoSQL >> MongoDB

Desnormalización con Mongoose:Cómo sincronizar cambios

Vale, mientras espero una respuesta mejor que la mía, intentaré publicar lo que he estado haciendo hasta ahora.

Middleware previo/posterior

Lo primero que intenté fue usar el pre/post middlewares para sincronizar documentos que se referencian entre sí. (Por ejemplo, si tiene Author y Quote , y un autor tiene una matriz del tipo:quotes: [{type: Schema.Types.ObjectId, ref:'Quotes'}] , luego, cada vez que se elimine una cotización, deberá eliminar su _id de la matriz. O si se elimina al autor, es posible que desee que se eliminen todas sus citas).

Este enfoque tiene una ventaja importante :si define cada esquema en su propio archivo, puede definir el middleware allí y tenerlo todo ordenado . Cada vez que mira el esquema, justo debajo puede ver lo que hace, cómo sus cambios afectan a otras entidades, 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.
    )
})

La principal desventaja sin embargo, estos ganchos no se ejecutan cuando llamas a update o cualquier función de actualización/eliminación estática del modelo . Más bien, debe recuperar el documento y luego llamar a save() o remove() en ellos.

Otra desventaja menor es que Quote ahora necesita estar al tanto de cualquier persona que lo haga referencia, para que pueda actualizarlos cada vez que se actualice o elimine un Quote. Así que digamos que un Period tiene una lista de citas y Author también tiene una lista de citas, Quote necesitará saber acerca de estas dos para actualizarlas.

La razón de esto es que estas funciones envían consultas atómicas a la base de datos directamente. Si bien esto es bueno, odio la inconsistencia entre usar save() y Model.Update(...) . Tal vez alguien más o usted en el futuro use accidentalmente las funciones de actualización estática y su middleware no se active, lo que le dará dolores de cabeza de los que luchará por deshacerse.

Mecanismos de eventos de NodeJS

Lo que estoy haciendo actualmente no es realmente óptimo, pero me ofrece suficientes beneficios para superar las desventajas (o eso creo, si alguien se preocupa por darme su opinión, sería genial). Creé un servicio que envuelve un modelo, digamos AuthorService que extiende events.EventEmitter y es una función de Constructor que se verá más o menos así:

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

Las ventajas:

  • Cualquier función interesada puede registrarse en Serviceevents y ser notificado. De esa forma, por ejemplo, cuando un Quote isupdated, AuthorService puede escucharlo y actualizar los Authors respectivamente. (Nota 1)
  • Quote no necesita estar al tanto de todos los documentos que hacen referencia a él, el Servicio simplemente activa el QuoteUpdated evento y todos los documentos que necesiten para realizar operaciones cuando esto suceda lo harán.

Nota 1:siempre y cuando este servicio se utilice cada vez que alguien necesite interactuar con mongoose.

Las desventajas:

  • Se agregó código repetitivo, utilizando un servicio en lugar de mongoose directamente.
  • Ahora no es exactamente obvio qué funciones se llaman cuando activas el evento.
  • Se separa productor y consumidor a costa de la legibilidad (ya que solo emit('EventName', args) , no es inmediatamente obvio qué servicios están escuchando este evento)

Otra desventaja es que alguien puede recuperar un Modelo del Servicio y llamar a save() , en el que los eventos no se activarán aunque estoy seguro de que esto podría solucionarse con algún tipo de híbrido entre estas dos soluciones.

Estoy muy abierto a sugerencias en este campo (es por eso que publiqué esta pregunta en primer lugar).