MongoDB
 sql >> Base de Dados >  >> NoSQL >> MongoDB

Desnormalização com Mongoose:Como sincronizar alterações


Ok, enquanto espero uma resposta melhor que a minha, vou tentar postar o que tenho feito até agora.

Pré/Pós Middleware

A primeira coisa que tentei foi usar os pré/pós middlewares para sincronizar documentos que faziam referência uns aos outros. (Por exemplo, se você tiver Author e Quote , e um autor tem uma matriz do tipo:quotes: [{type: Schema.Types.ObjectId, ref:'Quotes'}] , sempre que uma cotação for excluída, você terá que remover seu _id da matriz. Ou se o autor for removido, você pode querer que todas as suas citações sejam removidas).

Essa abordagem tem uma vantagem importante :se você definir cada Schema em seu próprio arquivo, poderá definir o middleware lá e ter tudo organizado perfeitamente . Sempre que você olhar para o esquema, logo abaixo você poderá ver o que ele faz, como suas alterações afetam outras 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.
    )
})

A principal desvantagem no entanto, esses ganchos não são executados quando você chama update ou qualquer função de atualização/remoção estática do modelo . Em vez disso, você precisa recuperar o documento e chamar save() ou remove() neles.

Outra desvantagem menor é que o Quote agora precisa estar ciente de qualquer pessoa que faça referência a ele, para que possa atualizá-los sempre que um Quote for atualizado ou removido. Digamos que um Period tem uma lista de citações e Author também tem uma lista de cotações, o Quote precisará saber sobre essas duas para atualizá-las.

A razão para isso é que essas funções enviam consultas atômicas diretamente ao banco de dados. Embora isso seja bom, eu odeio a inconsistência entre usar save() e Model.Update(...) . Talvez outra pessoa ou você no futuro use acidentalmente as funções de atualização estática e seu middleware não seja acionado, causando dores de cabeça das quais você luta para se livrar.

Mecanismos de evento NodeJS

O que estou fazendo atualmente não é realmente ótimo, mas me oferece benefícios suficientes para superar os contras (ou assim acredito, se alguém se importar em me dar algum feedback, seria ótimo). Eu criei um serviço que envolve um modelo, digamos AuthorService que estende events.EventEmitter e é uma função Construtor que será mais ou menos assim:
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()

As vantagens:
  • Qualquer função interessada pode se registrar no Serviceevents e ser notificada. Dessa forma, por exemplo, quando um Quote for atualizado, o AuthorService pode ouvi-lo e atualizar os Authors adequadamente. (Nota 1)
  • A cotação não precisa estar ciente de todos os documentos que a referenciam, o Serviço simplesmente aciona o QuoteUpdated evento e todos os documentos que precisam realizar operações quando isso acontecer o farão.

Observação 1:desde que este serviço seja usado sempre que alguém precisar interagir com o mangusto.

As desvantagens:
  • Adicionado código clichê, usando um serviço em vez de mangusto diretamente.
  • Agora não é exatamente óbvio quais funções são chamadas quando você aciona o evento.
  • Você dissocia produtor e consumidor ao custo de legibilidade (já que você apenas emit('EventName', args) , não é imediatamente óbvio quais Serviços estão ouvindo este evento)

Outra desvantagem é que alguém pode recuperar um modelo do serviço e chamar save() , em que os eventos não serão acionados embora eu tenha certeza de que isso possa ser resolvido com algum tipo de híbrido entre essas duas soluções.

Estou muito aberto a sugestões neste campo (e é por isso que postei essa pergunta em primeiro lugar).