Atualizar ou inserir várias linhas do MySQL - Raw Laravel SQL

Atualizar ou inserir várias linhas do MySQL - Raw Laravel SQL

Problema

Tenho mensagens no sistema enviado entre várias pessoas como um bate -papo em grupo. Toda vez que alguém vai para carregar mensagens (abre sua caixa de entrada), preciso que essas mensagens sinalizem como lida. Não tenho um modelo eloqüente para a tabela Direct_Message_Read_At Pivot, e estou usando uma classe que encapsula a classe DB Laravel para escrever uma consulta MySQL personalizada para fazer isso.

Meu problema é: como faço para evitar entradas duplicadas se alguém abrir o tópico da mensagem 10 vezes e fazer com que o timestamp atualizado? (Já que eles abrirão o mesmo tópico de mensagem várias vezes)

Solução

Para ajudar na configuração desta solução, vamos primeiro mostrar como criamos esta tabela usando a migração de Laravel:

Antes do pivô, criamos uma tabela de mensagens para armazenar todas as mensagens das pessoas. Depois disso, criamos a tabela de articulação.

Schema :: Create ('Direct_Message_Read_at', function (Blueprint $ tabela)
$ tabela-> incrementos ('id');
$ tabela-> integer ('message_id')-> não assinado ()-> anulável ();
$ tabela-> estrangeiro ('message_id')-> referências ('id')-> on ('diretor_messages')-> ondelete ('cascade');
$ tabela-> integer ('user_id')-> não assinado ()-> anulável ();
$ tabela-> estrangeiro ('user_id')-> referências ('id')-> on ('usuários')-> ondelete ('cascade');
$ tabela-> Inteiro ('Organização_id')-> Unsigned ()-> Nullable ();
$ tabela-> estrangeiro ('organização_id')-> referências ('id')-> on ('organizações')-> ondelete ('cascade');
$ tabela-> timestamps ();
$ tabela-> exclusivo (['message_id', 'user_id', 'organização_id']); // isso é realmente importante para
impedir entradas duplicadas pela mesma pessoa
);

Agora, queremos criar um evento e um ouvinte que processará as mensagens carregadas.

Imagine que você tem uma classe responsável por carregar todas as suas mensagens (quando você abre sua caixa de entrada)

Função pública LoadMessages ()

$ thread_messages = DirectMessage :: All ();
$ message_ids = $ this-> removeMymeSessages ($ thread_messages)
Evento (new MessageRead ($ mensagens_ids));

RemoveMymessages de função protegida ($ mensagens)

$ message_ids = [];
// Simplesmente filtra todas as mensagens enviadas por você usando 'Where (' Sender_id ',
auth ()-> user ()-> id)-use sua própria lógica de código para fazer isso
retornar $ message_ids;

Agora, dentro da leitura das mensagens, você pode defini -las e passá -las para o ouvinte

Mensagens de classe

use despacho, interraeswithsockets, serializa models;
public $ mensagens_ids = [], $ user_id, $ organização_id;
/**
* Crie uma nova instância de evento.
*
* @return void
*/
função pública __construct ($ message_ids = [])

$ this-> message_ids = $ message_ids;
$ this-> user_id = auth ()-> user ()-> id;
$ this-> organização_id = auth ()-> user ()-> organização_id;

/**
* Obtenha os canais que o evento deve transmitir.
*
* @return \ iluminate \ broadcasting \ canal | Array
*/
Função pública Broadcaston ()

devolver o novo privatechannel ('canal-name');

Dentro do ouvinte que você definiu anteriormente no EventServiceProvider, você pode ligar para sua classe para processar a atualização da tabela Pivot

Classe MarkMessagesAsRead

/**
* Crie o ouvinte do evento.
*
* @return void
*/
Função pública __construct ()

//

/**
* Lidar com o evento.
*
* @Param MessageRead $ Evento
* @return void
*/
Handle de função pública (Evento MessageRead $)

$ message_ids = $ event-> messages_ids;
$ user_id = $ event-> user_id;
$ organização_id = $ event-> organização_id;
(novo CreateRectMessageReadIndicator (novo db))-> Execute ($ message_ids, $ user_id,
$ organização_id);

E finalmente, estamos chegando mais perto do fim. Tudo o que precisamos fazer agora é realmente olhar para a consulta MySQL

CLASSE CREATEDIRECTMESSAGEREADIDICATOR

$ db protegido;
função __construct (db $ db)

$ this-> dB = $ dB;

/**
* Construa e retorne a cláusula selecionada para a consulta
*
* @return string
*/
função pública Execute ($ message_ids = [], $ user_id, $ organização_id)

if (count ($ message_ids) <= 0)
retorna falso;

$ criate_at = date ('y-m-d h: i: s');
$ update_at = date ('y-m-d h: i: s');
$ parâmetros = [];
foreach ($ message_ids como $ message_id)
Array_push ($ parâmetros, "($ message_id, $ user_id, $ organização_id,
'$ creted_at') ");

$ parameters_string = implode (",", $ parâmetros);
$ query = "
Inserir em diretor_message_read_at (message_id, user_id, organização_id,
criado em)
Valores
$ parâmetros_string
Na Key Duplicate Key Update Update_at = "$ UPDATED_AT";
";
$ this-> db :: select ($ query);

Então, o que acabou de acontecer aqui. Basicamente, marcamos message_id, user_id e organização_id como a combinação única. Caso o mesmo user_id que pertence à mesma organização organização_id abre a mesma mensagem de alguém que tem esse Message_id, ele lançará o erro de duplicação do MySQL.

Quando você insere uma nova linha em uma tabela se a linha causar uma duplicata em índice exclusivo ou chave primária, o MySQL emitirá um erro.

No entanto, se você especificar a opção de atualização de chaves on duplicados na instrução Insert, o MySQL atualizará a linha existente com os novos valores em vez disso.

https: // www.mysqltutorial.org/mysql-insert-or-update-on-duplicate-key-update/
Deixe -me compartilhar algumas capturas de tela.

A primeira mensagem sendo lida:

Inserir em diretor_message_read_at (message_id, user_id, organização_id, criado_at)
Valores
(75, 3, 1, '2020-01-16 15:00:00')
Na Key Duplicate Key Update Atualizada_at = "2020-01-17 22:00:00"

Ele produzirá esta entrada no banco de dados:

Então você volta e lê a mesma mensagem amanhã, ela fará com que apenas a coluna atualizada_at seja atualizada:

Dessa forma, você sabe quando a mensagem foi vista pela primeira vez e quando foi a última vez que a mensagem foi lida.