Multi-action and content notification system

Asked

Viewed 389 times

1

I am trying to understand how best to make a notification scheme for multiple actions and nodes. Basically one should notify someone whenever an action of the type message or enjoy is performed.

Message: Fulano de tal enviou uma mensagem

       Enjoyed: Fulano de tal curtiu seu texto [prévia com texto]


The problem is to relate all this, because an accurate case of the user name and in another case relate to recover the text and link.

select
case tipo
    when 'mensagem' then ( [...] )
    when 'curtiu'   then ( select concat( nome , '//' , acao , '//' , body ) from tabela
                           inner join [...] where [...] )
end `data`
from notificacao

As it is line-line, I thought to make a simple select with subquery in each case depending on the type of notification, use concat and explode to break the elements. The above query would return lines as Papa Cahrlie//curtiu//Lorem ipsum....

In this scheme each type would have a subquery, but I have more 'events' besides the example, and I will have more complex querys. I could even resort to views if applicable.


TABLE:

CREATE TABLE `notificacao` (
  `ID` int(11) NOT NULL AUTO_INCREMENT,
  `USUARIO` int(11) DEFAULT NULL,
  `CONTEUDO` int(11) DEFAULT NULL,
  `TIPO` enum( '...' ),
  `STATUS` enum( '0' , '1' ) DEFAULT '0',
)

My table is simple - generic - that records the user, the type of event and the reference of the content that suffered the action. Wanted opinions on working this select more simply and/ or efficiently.

1 answer

2

I suggest you create a master table of notifications and two daughter tables; one for message notifications and one for likes notifications:

CREATE TABLE notificacao (
    notificacao_id INT NOT NULL AUTO_INCREMENT,
    lida BOOLEAN NOT NULL DEFAULT FALSE,
    data_criacao DATETIME NOT NULL,
    -- outros campos, e.g. data/hora que a notificação foi lida…
    -- você pode também desnormalizar o banco de dados e colocar aqui o id do usuário
    PRIMARY KEY (notificao_id));

CREATE TABLE notificacao_mensagem (
    notificacao_id INT NOT NULL,
    mensagem_id INT NOT NULL,
    PRIMARY KEY (notificacao_id),
    FOREIGN KEY (notificacao_id) REFERENCES notificacao,
    FOREIGN KEY (mensagem_id) REFERENCES mensagem (id));

CREATE TABLE notificacao_curtida (
    notificacao_id INT NOT NULL,
    curtida_id INT NOT NULL,
    PRIMARY KEY (curtida_id),
    FOREIGN KEY (notificacao_id) REFERENCES notificacao,
    FOREIGN KEY (curtida_id) REFERENCES curtida (id));

When you need to know who likes who, you make the appropriate Join. If you need to pull everything into a table only later, you can compose a view using LEFT OUTER Joins:

CREATE VIEW notificacao AS
SELECT
    …
FROM
    notificacao
    LEFT OUTER JOIN (
        notificacao_mensagem
        INNER JOIN mensagem ON …condição…) USING (notificacao_id)
    LEFT OUTER JOIN (
        notificacao_curtida
        INNER JOIN curtida ON …condição…) USING (notificacao_id)
    …outras notificações…

You would differentiate the types of notification by the presence of Nulls - only the likes would have notificao_curtida.curtida_id IS NOT NULL, for example.

  • Thank you, but as I said in the question, for every action there is a different relationship. 'Likes' relates to text to display a preview, and messages only need the author. Maybe the use of UNION ALL can replace the CASE, but it doesn’t solve relationships.

  • I didn’t understand the problem of relationships; the idea of separating notifications into tables is exactly to allow JOIN from messages notifications with the message tables and JOIN from likes notifications with the likes tables. What you have in mind that it would be impossible to do the scheme this way?

  • Message only needs to notify that X sent message to Y; Likes relates to X that Y likes text Lorem ipsum...; UNION ALL will not work because they are relationships for different fields.

  • If the notifications are too heterogeneous to inhabit a single table, you have to make two queries: one for the likes, another for the messages - the solution with CONCAT/EXPLODE only works until someone puts in your database some string with the delimiter you chose (accidentally or maliciously), and then your PHP will break all the wrong fields... You can implement an Escaping system, but then every time you put or take something from the database you will need to do and undo Escaping.

  • Yeah, it’s crossed my mind this inconvenience. Making 2 separate queries will be a problem sort by date.

  • I edited my reply for it to become a solution with LEFT OUTER Joins - you’ll get a clogged table of Nulls, but you’ll be able to have separate columns for separate notifications, and sort by date.

Show 1 more comment

Browser other questions tagged

You are not signed in. Login or sign up in order to post.