Compreendendo um sistema de notificação

14

Eu estive estudando como criar um sistema de notificação no SE e em outros lugares e me senti atraído pela solução que é a resposta aceita aqui: /programming/9735578/building-a-notification-system que usa esta estrutura:

╔═════════════╗      ╔═══════════════════╗      ╔════════════════════╗
notification       notification_object      notification_change 
╟─────────────╢      ╟───────────────────╢      ╟────────────────────╢
ID           ║—1:n—→║ID                 ║—1:n—→║ID                  
userID             notificationID           notificationObjectID
╚═════════════╝      object                   verb                
                     ╚═══════════════════╝      actor               
                                                ╚════════════════════╝

Uma notificação é sobre algo (objeto = evento, amizade ..) sendo alterado (verbo = adicionado, solicitado ..) por alguém (ator) e relatado ao usuário (sujeito). Aqui está uma estrutura de dados normalizada (embora eu tenha usado o MongoDB). Você precisa notificar certos usuários sobre alterações. Portanto, são notificações por usuário. Ou seja, se houver 100 usuários envolvidos, você gera 100 notificações.

A princípio, pensei que havia compreendido essa abordagem, mas quando comecei a me preparar para implementá-la, percebi que aparentemente não a entendia particularmente bem. Os últimos comentários sobre a resposta são perguntas de outros usuários que também tiveram problemas para entender a solução.

Não tenho certeza se esse é o modelo que acabarei seguindo, mas, dado o número de votos que ele possui, tenho certeza de que me beneficiaria de entendê- lo, e certamente gostaria de aprender mais. Espero que isso também seja útil para outras pessoas que tiveram problemas para entender essa solução (aliás, não tenho pontos de internet suficientes para deixar um comentário sobre a resposta direcionada a essa pergunta, mais alguém por favor!)

Questões

Se entendi direito, notificationObjectID é uma chave estrangeira para a notification_object mesa, e notificationID é uma chave estrangeira apontando para a notificação de mesa. Parece que o objeto deve ser uma chave estrangeira referente ao ID da entrada do banco de dados da qual a notificação se refere (por exemplo, um evento ou publicação específica), mas não precisamos de outro campo para indicar a qual tabela esse ID pertence?

O autor escreveu

notification_object.object identifica o tipo de alteração, como uma string "friendship" A referência real ao objeto alterado com seus dados extras sobre os quais falo está em notification_change.notificationObjectID

o que não parece fazer sentido para mim. O objeto é uma string (enum?) E notificationObjectID é uma chave estrangeira que se refere ao objeto sobre o qual a notificação se refere? Então, como as tabelas do meio e da direita estão conectadas?

Parece que a tabela do meio especifica sobre qual objeto (ou tipo de objeto) a notificação se refere, por exemplo, um evento ou publicação. Podemos então ter muitas entradas em notification_change que apontam para o mesmo tipo de objeto, o que nos permite agrupar notificações (como "25 usuários postados no mural de X) - daí o relacionamento 1: n entre as tabelas do meio e da direita.

Mas por que existe uma relação 1: n entre as tabelas esquerda e do meio? Vamos dar a "25 usuários postados no mural de Sam" e "Mary atualizou seu evento" Friday Picnic "o mesmo ID de notificação? Se todas as notificações para o mesmo usuário tiverem o mesmo ID de notificação, por que precisamos da tabela na tabela esquerda?

Uma questão de desempenho - digamos, John postou um comentário no evento de piquenique de Mary. Parece que precisamos fazer uma pesquisa para ver se já existe um objeto de notificação para o Mary's Picnic antes de criarmos a entrada notification_change . Isso afetará negativamente o desempenho ou não será um problema? Continuando as perguntas do parágrafo anterior, como saberíamos para qual entrada de notificação apontar o objeto notification_object ?

user45623
fonte

Respostas:

8

Obrigado por essas perguntas completas e desculpe por toda a confusão - comentar 1 ano após a resposta inicial é difícil e agora 3 anos depois .. os pensamentos iniciais desaparecem e me confundem também, mas eu tenho medo de editar a coisa do buraco porque não estou trabalhando sobre o armazenamento de notificações no back-end agora e não tenho certeza se eu faço bons julgamentos sem aplicação prática

Eu acho que no momento da escrita:

  • Sim e não, notificationID era uma chave estrangeira, notificationObjectID não. Você precisa de outro campo FK para amarrar as tabelas. Eu culpo minha experiência mongo por não ser tão claro sobre isso :(
  • Sim e não, notification_object.object é vago porque você pode tê-lo apenas como uma sequência ou como algo complexo (JSON ou FK). No meu caso, era apenas um substantivo.

Portanto, tudo depende da aparência das suas notificações. Para simplificar, você só deseja vincular a notificação inteira a algum URL, como a página de amigos - é por isso que ter um objeto (entityType) como uma string é útil - você vincula URLs a ele.

A notificação "você tem 3 pedidos de amizade adicionados" pode ser armazenada de maneira diferente.

Se você quiser mostrá-los um de cada vez - você terá 3 notificações, 3 objetos de notificação (solicitação de amigo) e 3 entradas em notification_change que vinculam a um usuário amigo específico.

Se você quiser mostrar uma notificação - você terá 1 notificação, 1 / mais objetos e 3 / mais ações. Portanto, neste caso complexo, como «você tem 3 solicitações de amizade do usuário A, usuário B, usuário C» - você usa notificationObjectIDs para cada usuário e possui vários links no texto da notificação.

Você deve usar 1 ou 3 objetos friend_request? Isso depende de

  1. Qual é o objeto e qual é a ação. O «artigo gostou / comentou»? Ou é "like / comment added" e a hierarquia de objetos é vinculada apenas durante a exibição? Aqui está o facebook, distinguindo "comentário em foto" e "usuário mencionando", que semanticamente parecem estar muito próximos - você tem a mesma foto, o mesmo ator, mas notificações diferentes que poderiam ter sido mescladas

insira a descrição da imagem aqui

  1. Você pode remover uma notificação ou precisa de um histórico? Portanto, se eu enviar uma solicitação de amizade e, em seguida, cancelá-la, comentar ou excluir um artigo, como algo diferente de algo - deve mostrar esse histórico (como outra ação) ao usuário final como duas ações diferentes? Provavelmente não. Além disso, é tecnicamente mais complexo - você precisa pesquisar se existe um objeto de notificação existente, adicionar uma nova notificação_change a ele (se não houver - adicionar um novo objeto), para que mais tarde eu precise pesquisar através de notification_change para removê-lo. Em vez disso, basta adicionar outro objeto de notificação à mesma notificação e removê-lo se houver ações que foram excluídas em cascata.

Por outro lado, pode haver casos em que pode ser útil agrupar ações em que nada é apagado da história.

Eu acho que é por isso que, no momento da redação deste artigo, a relação 1: n entre as tabelas esquerda e do meio foi feita - para que você pudesse agrupar as notificações não apenas pelos atores da mesma entidade (tabelas do meio à direita), mas também por vários objetos / entidades.

Mas com certeza, você pode simplificar todo o caso e otimizar o armazenamento revertendo o relacionamento meio-esquerdo para n: 1, para que você tenha notificações geradas por usuário para um evento.

Para que parecesse mais com isso ..

╔═════════════╗      ╔═══════════════════╗      ╔════════════════════╗
notification       notification_object      notification_change 
╟─────────────╢      ╟───────────────────╢      ╟────────────────────╢
ID           ║←—n:1—║ID                 ║—1:n—→║ID                  
noteObjFK          entityType               noteObjFK           
viewerUserID       entityID                 actionOnEntity      
╚═════════════╝      ╚═══════════════════╝      actorUserID         
                                                ╚════════════════════╝

Espero que isso tenha ajudado

Artjom Kurapov
fonte
Ótimo, obrigado por esta resposta completa. Vou passar por isso e informá-lo se tiver mais alguma dúvida, mas acho que isso explica muito bem as coisas.
User45623