Aggiornamento MySQL o inserire più righe - Raw Laravel SQL

Aggiornamento MySQL o inserire più righe - Raw Laravel SQL

Problema

Ho messaggi nel sistema inviati tra più persone come chat di gruppo. Ogni volta che qualcuno va a caricare i messaggi (apre la loro casella di posta), ho bisogno di contrassegnare quei messaggi come letto. Non ho un modello eloquente per la tabella pivot direct_message_read_at e sto usando una classe che incapsula la classe DB Laravel per scrivere una query MySQL personalizzata per farlo.

Il mio problema è che come posso impedire le voci duplicate se qualcuno apre il thread del messaggio 10 volte e la modifica del timestamp aggiornato_at ogni volta che leggono il messaggio? (Poiché apriranno lo stesso thread di messaggi più volte)

Soluzione

Per aiutare con la configurazione di questa soluzione, mostriamo per la prima volta come creiamo questa tabella usando la migrazione di Laravel:

Prima del perno, avremmo creato una tabella di messaggi per archiviare tutti i messaggi dalle persone. Dopodiché creiamo la tabella dei perni.

Schema :: create ('Direct_message_read_at', funzione (Blueprint $ table)
$ table-> increment ('id');
$ table-> integer ('message_id')-> unsigned ()-> nulllable ();
$ tabella-> straniero ('message_id')-> riferimenti ('id')-> on ('Direct_messages')-> ondelete ('cascade');
$ table-> integer ('user_id')-> unsigned ()-> nulllable ();
$ table-> straniero ('user_id')-> riferimenti ('id')-> on ('utenti')-> ondelete ('cascade');
$ table-> integer ('organizzation_id')-> unsigned ()-> nulllable ();
$ tabella-> straniero ('organizzazione_id')-> riferimenti ('id')-> su ('organizzazioni')-> ondelete ('cascade');
$ table-> timestamps ();
$ table-> univoco (['message_id', 'user_id', 'organizzation_id']); // Questo è davvero importante per
Prevenire le voci duplicate da parte della stessa persona
);

Ora, vogliamo creare un evento e un ascoltatore che elaborerà i messaggi caricati.

Immagina di avere una lezione responsabile del caricamento di tutti i tuoi messaggi (quando apri la tua casella di posta)

Funzione pubblica LoadMessages ()

$ thread_messages = directMessage :: all ();
$ message_ids = $ this-> removemymessages ($ thread_messages)
event (new MessageRead ($ Message_ids));

Funzione protetta Rimovemymessages ($ Messaggi)

$ message_ids = [];
// Filtra semplicemente tutti i messaggi inviati dall'utente utilizzando "Where ('Sender_ID',
AUTH ()-> User ()-> ID)-Usa la tua logica di codice per farlo
return $ message_ids;

Ora all'interno del READREAD puoi definirli e passarli all'ascoltatore

Messaggi di classe READ

Usa spedire, interagisce con i documenti, model di serialico;
public $ Messaggi_ids = [], $ user_id, $ organizzation_id;
/**
* Crea una nuova istanza di eventi.
*
* @return void
*/
funzione pubblica __Construct ($ message_ids = [])

$ this-> Message_ids = $ message_ids;
$ this-> user_id = auth ()-> user ()-> id;
$ this-> Organization_id = auth ()-> user ()-> Organizzazione_id;

/**
* Ottieni i canali su cui l'evento dovrebbe trasmettere.
*
* @return \ illuminate \ broadcasting \ canale | array
*/
Funzione pubblica Broadcaston ()

restituire nuovo privatechannel ('canale-nome');

All'interno dell'ascoltatore che hai definito in precedenza in EventServiceProvider puoi chiamare la tua classe per elaborare l'aggiornamento della tabella pivot

Classe MarkMessagesAsRead

/**
* Crea l'ascoltatore di eventi.
*
* @return void
*/
funzione pubblica __construct ()

//

/**
* Gestisci l'evento.
*
* @param Messaggired $ evento
* @return void
*/
Handle di funzione pubblica (Messaggi READ $ Event)

$ message_ids = $ event-> message_ids;
$ user_id = $ event-> user_id;
$ organizzazioni_id = $ event-> Organization_id;
(Nuovo creatorectMessagereADindicator (new DB))-> Esecute ($ message_ids, $ user_id,
$ organizzazioni_id);

E infine, ci stiamo avvicinando alla fine. Tutto quello che dobbiamo fare ora è guardare effettivamente la query MySQL

Classe CreateCirectMessagerIndicatore

protetto $ db;
funzione __construct (db $ db)

$ this-> db = $ db;

/**
* Build e restituire la clausola seleziona per la query
*
* @return String
*/
Funzione pubblica Execute ($ message_ids = [], $ user_id, $ organizzation_id)

if (count ($ message_ids) <= 0)
restituire false;

$ created_at = date ('y-m-d h: i: s');
$ updated_at = date ('y-m-d h: i: s');
$ parametri = [];
foreach ($ message_ids come $ message_id)
Array_Push ($ parametri, "($ message_id, $ user_id, $ organizzation_id,
'$ created_at') ");

$ parametri_string = implode (",", $ parametri);
$ query = "
Inserisci in direct_message_read_at (message_id, user_id, organizzazione_id,
creato_at)
VALORI
$ parametri_string
Su Duplica Key Update updated_at = "$ updated_at";
";
$ this-> db :: Select ($ query);

Allora quello che è appena successo qui. Fondamentalmente abbiamo contrassegnato Message_id, user_id e Organization_id come combinazione univoca. Nel caso in cui lo stesso user_id appartenga alla stessa organizzazione organizzazione_id apre lo stesso messaggio da qualcuno che ha quel messaggio_id, lancerà un errore di duplicazione MySQL.

Quando si inserisce una nuova riga in una tabella se la riga provoca un duplicato nell'indice univoco o nella chiave primaria, MySQL emetterà un errore.

Tuttavia, se si specifica l'opzione di aggiornamento della chiave Duplicate nell'istruzione Insert, MySQL aggiornerà invece la riga esistente con i nuovi valori.

https: // www.mysqlturial.org/mysql-insert-o-update-on-duplicato-key-update/
Fammi condividere alcuni screenshot.

Il primo messaggio viene letto:

Inserisci in direct_message_read_at (message_id, user_id, organizzation_id, created_at)
VALORI
(75, 3, 1, '2020-01-16 15:00')
Su duplicato aggiornamento chiave aggiornato_at = "2020-01-17 22:00:00"

Produrrà questa voce nel database:

Quindi torni e leggi lo stesso messaggio domani, causerà l'aggiornamento solo della colonna aggiornata_at:

In questo modo sai quando il messaggio è stato visto per la prima volta e quando è stata l'ultima volta in cui il messaggio è stato letto.