Implementando comentários e curtidas no banco de dados


146

Sou desenvolvedor de software. Adoro codificar, mas odeio bancos de dados ... Atualmente, estou criando um site no qual um usuário poderá marcar uma entidade como curtida (como no FB), marcá- la e comentar .

Fico preso no design de tabelas de banco de dados para lidar com essa funcionalidade. A solução é trivial, se pudermos fazer isso apenas para um tipo de coisa (por exemplo, fotos). Mas preciso habilitar isso para cinco coisas diferentes (por enquanto, mas também presumo que esse número possa crescer à medida que o serviço inteiro cresce).

Encontrei algumas perguntas semelhantes aqui, mas nenhuma delas tem uma resposta satisfatória, por isso estou fazendo essa pergunta novamente.

A questão é: como projetar o banco de dados de maneira adequada, eficiente e elástica , para que ele possa armazenar comentários para tabelas diferentes , curtidas para tabelas e tags diferentes para elas. Algum padrão de design como resposta será melhor;)

Descrição detalhada : Eu tenho uma tabela User com alguns dados do usuário e mais 3 tabelas : Photocom fotografias , Articlescom artigos , Placescom lugares . Quero habilitar qualquer usuário logado para:

  • comentar em qualquer uma dessas 3 tabelas

  • marque qualquer um deles como desejado

  • marcar qualquer um deles com alguma tag

  • Também quero contar o número de curtidas para cada elemento e o número de vezes que essa tag específica foi usada.

1 r abordagem :

a) Para as tags , vou criar uma tabela Tag [TagId, tagName, tagCounter] , então eu vou criar muitos-para-muitos relacionamentos mesas para: Photo_has_tags, Place_has_tag, Article_has_tag.

b) O mesmo vale para comentários.

c) I irá criar uma tabela LikedPhotos [idUser, idPhoto] , LikedArticles[idUser, idArticle], LikedPlace [idUser, idPlace]. O número de curtidas será calculado por consultas (que, suponho, são ruins). E...

Eu realmente não gosto deste design para a última parte, ele cheira muito mal para mim;)


2 nd abordagem :

Vou criar uma tabela ElementType [idType, TypeName == some table name]que será preenchida pelo administrador (eu) com os nomes das tabelas que podem ser curtidas , comentadas ou marcadas . Então eu vou criar tabelas :

a) LikedElement [idLike, idUser, idElementType, idLikedElement]e o mesmo para Comentários e Tags com as colunas apropriadas para cada um. Agora, quando eu quiser fazer uma foto curtida, inserirei:

typeId = SELECT id FROM ElementType WHERE TypeName == 'Photo'
INSERT (user id, typeId, photoId)

e para lugares:

typeId = SELECT id FROM ElementType WHERE TypeName == 'Place'
INSERT (user id, typeId, placeId)

e assim por diante ... Acho que a segunda abordagem é melhor, mas também sinto que algo está faltando nesse design ...

Por fim, também me pergunto qual é o melhor local para armazenar o contador quantas vezes o elemento foi curtido. Só consigo pensar em duas maneiras:

  1. na Photo/Article/Placetabela element ( )
  2. por contar count ().

Espero que minha explicação sobre o assunto seja mais completa agora.


Você já considerou XML?
CodyBugstein

1
Eu raramente encontro perguntas como essa que são 100% do que tenho em mente, sua pergunta é incrivelmente completa! Obrigado @Kokos.
aderchox

Respostas:


195

A solução mais extensível é ter apenas uma tabela "base" (conectada a "curtidas", tags e comentários) e "herdar" todas as outras tabelas dela. Adicionar um novo tipo de entidade envolve apenas adicionar uma nova tabela "herdada" - ela se conecta automaticamente a toda a maquinaria como / tag / comment.

O termo de relacionamento da entidade para isso é "categoria" (consulte o Guia de Métodos do ERwin , seção: "Relacionamentos de subtipos"). O símbolo da categoria é:

Categoria

Supondo que um usuário possa gostar de várias entidades, uma mesma tag pode ser usada para mais de uma entidade, mas um comentário é específico da entidade, e seu modelo pode ficar assim:

Diagrama ER


BTW, existem aproximadamente três maneiras de implementar a "categoria ER":

  • Todos os tipos em uma tabela.
  • Todos os tipos de concreto em tabelas separadas.
  • Todos os tipos concretos e abstratos em tabelas separadas.

A menos que você tenha requisitos de desempenho muito rigorosos, a terceira abordagem é provavelmente a melhor (o que significa que as tabelas físicas correspondem 1: 1 às entidades no diagrama acima).


2
ótima resposta, obrigado. Espero que eu consiga implementá-lo ... e gostaria de saber como o Django ORM lidará com o mapeamento (ou como farei isso sozinho ... mas esse é o outro problema;)) Mas, você pode explicar eu, porque acho que não entendi direito - o que você desenhou para mim (obrigado!) é a terceira abordagem que você mencionou?
Kokos

2
@Kokos Essencialmente, a abordagem (3) significa que ENTITY é uma tabela, PHOTO é uma tabela, ARTIGO é uma tabela e PLACE é uma tabela. A abordagem (2) significaria que não tabela para ENTITY e a abordagem (1) significaria que havia apenas uma tabela. A existência de todas essas abordagens (todas com seus pontos fortes e fracos) é a conseqüência infeliz do fato de que um RDBMS típico não suporta nativamente a herança de tabelas.
Branko Dimitrijevic

1
+1 obrigado pela ótima explicação e referências em "categorias". Eu ia postar uma pergunta perto disso, mas você respondeu aqui.
55580 Andy On-line:

2
@BrankoDimitrijevic Por que as tabelas de entidades Foto, Artigo e Local não podem ter seu próprio PK, por exemplo, PhotoID, ArticleID etc, mas também possuem outra coluna para o Entity_ID como um FK? Isso é desnecessário?
volume one

3
@Orion O máximo para BIGINTé 9223372036854775807. Supondo que você insira uma linha por segundo, os valores disponíveis acabarão em ~ 300 bilhões de anos. Certamente, você poderá portar números inteiros de 128 bits até lá!
Branko Dimitrijevic

22

Como você "odeia" bancos de dados, por que você está tentando implementar um? Em vez disso, solicite ajuda de alguém que ama e respira essas coisas.

Caso contrário, aprenda a amar seu banco de dados. Um banco de dados bem projetado simplifica a programação, projeta o site e facilita sua operação contínua. Mesmo um designer de d / b experiente não terá uma previsão completa e perfeita: algumas mudanças de esquema no futuro serão necessárias conforme os padrões de uso surgirem ou os requisitos mudarem.

Se este for um projeto individual, programe a interface do banco de dados em operações simples usando procedimentos armazenados: add_user, update_user, add_comment, add_like, upload_photo, list_comments, etc. Não incorpore o esquema em nem uma linha de código. Dessa maneira, o esquema do banco de dados pode ser alterado sem afetar nenhum código: apenas os procedimentos armazenados devem saber sobre o esquema.

Pode ser necessário refatorar o esquema várias vezes. Isto é normal. Não se preocupe em aperfeiçoá-lo pela primeira vez. Basta torná-lo funcional o suficiente para criar um protótipo de um design inicial. Se você tiver o luxo do tempo, use-o um pouco e exclua o esquema e faça-o novamente. É sempre melhor na segunda vez.


2
Porque eu preciso implementá-lo sozinho. Pelo menos por enquanto ... e, pensei que talvez seja uma boa ocasião para começar a gostar um pouco de bancos de dados;) Obrigado pela sua sugestão com o procedimento armazenado. Alguém sabe, se eles são mapeados pelo Django ORM automaticamente?
Kokos

6
Eu amo sua última frase - é sempre melhor na segunda vez.
Lewis

2
É sempre melhor na segunda vez. Yup
Gammer

20

Esta é uma idéia geral, por favor, não preste muita atenção ao estilo dos nomes dos campos, mas mais à relação e estrutura

insira a descrição da imagem aqui

Este pseudocódigo obterá todos os comentários da foto com o ID 5
SELECT * FROM ações
WHERE actions.id_Stuff = 5
AND actions.typeStuff = "photo"
AND actions.typeAction = "comment"

Esse pseudocódigo obterá todos os gostos ou usuários que curtiram a foto com o ID 5
(você pode usar count () para obter apenas o número de curtidas)

SELECT * FROM actions  
WHERE actions.id_Stuff = 5  
AND actions.typeStuff="photo"  
AND actions.typeAction = "like"  

Eu acho que você pode até gostar de comentários, clicando em um link "like" em um comentário. Esta consulta obterá os gostos de um comentário (ação) com o ID 133: SELECT * FROM actions WHERE actions.id=133 AND actions.typeStuff = "comment" AND actions.typeAction = "like"
user964260 15/11/11

1
Definitivamente vou lembrar esta solução para novas versões do meu sistema :)
Kokos

Eu tenho 2 tabelas de itens stuff1 e stuff2 ... Eu segui esse diagrama, mas há erro sql ao usar isso ... stuff1, stuff2 são duas tabelas independentes com suas chaves primárias independentes e a tabela de ação possui uma coluna id_stuff à qual se refere essas duas tabelas stuff1, stuff2. Agora, por exemplo, stuff1 tem 5 linhas, stuff2 tem 10 linhas, quando tento adicionar linha na tabela de ações com id_stuff, qualquer coisa menor que 5, digamos '3', ele executa a consulta porque existe uma linha com id_stuff '3' em ambos os stuff1 e stuff2, mas se eu tentar adicionar linha com maior id_stuff que 5 ... (continuar para o próximo comentário)
vikas devde

1
Se alguém implementa gostos dessa maneira, torna mais difícil notificar o usuário dos novos gostos. Isso exigiria outra tabela.
Greg L

4
Como a id_stuffcoluna conterá valores exclusivos em cada uma das três tabelas?
volume one

0

Tanto quanto eu entendo. várias tabelas são necessárias. Existe uma relação de muitos para muitos entre eles.

  • Tabela que armazena os dados do usuário como nome, sobrenome e data de nascimento com um campo de identidade.
  • Tabela que armazena tipos de dados. esses tipos podem ser fotos, compartilhamentos, links. cada tipo deve ter uma tabela exclusiva. portanto, existe uma relação entre suas tabelas individuais e esta tabela.
  • cada tipo de dados diferente tem sua tabela. por exemplo, atualizações de status, fotos, links.
  • a última tabela é para muitos para armazenar um ID, ID de usuário, tipo de dados e ID de dados.

se você postar o diagrama do banco de dados. Eu posso desenhar a relação.
erencan

0

Veja os padrões de acesso necessários. Algum deles parece tornar particularmente difícil ou ineficiente minha escolha de um projeto ou outro?

Se não favorecer o que requer menos tabelas

Nesse caso:

  1. Adicionar comentário: você escolhe uma determinada tabela com muitas / muitas ou insere uma tabela comum com um identificador específico conhecido para o que está sendo apreciado; acho que o código do cliente será um pouco mais simples no seu segundo caso.
  2. Encontre comentários para o item: aqui parece que usar uma tabela comum é um pouco mais fácil - só temos uma única consulta parametrizada por tipo de entidade
  3. Encontre comentários de uma pessoa sobre um tipo de coisa: consulta simples em ambos os casos
  4. Encontre todos os comentários de uma pessoa sobre todas as coisas: isso parece pouco complicado de qualquer maneira.

Eu acho que sua abordagem "discriminada", opção 2, gera consultas mais simples em alguns casos e não parece muito pior nos outros, então eu continuaria.


0

Definitivamente, vá com a segunda abordagem, na qual você tem uma tabela e armazena o tipo de elemento para cada linha, ela oferece muito mais flexibilidade. Basicamente, quando algo pode ser feito logicamente com menos tabelas, é quase sempre melhor usar menos tabelas. Uma vantagem que me vem à mente agora sobre o seu caso específico, considere que você deseja excluir todos os elementos desejados de um determinado usuário. Com a sua primeira abordagem, é necessário emitir uma consulta para cada tipo de elemento, mas com a segunda abordagem, isso pode ser feito com apenas uma consulta ou considere quando você deseja adicionar um novo tipo de elemento, com a primeira abordagem envolve a criação de uma nova tabela para cada novo tipo, mas com a segunda abordagem, você não deve fazer nada ...


-1

Considere usar tabela por entidade para comentários e etc. Mais tabelas - melhor sharding e dimensionamento. Não é um problema controlar muitas tabelas semelhantes para todas as estruturas que conheço.

Um dia, você precisará otimizar as leituras dessa estrutura. Você pode criar facilmente tabelas de agregação sobre as de base e perder um pouco nas gravações.

Uma grande mesa com dicionário pode se tornar incontrolável um dia.


Mais tabelas significa que será menos sustentável. Tabelas individuais podem ser divididas pela maioria dos d / bs.
wallyk
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.