Actualizar mysql o insertar múltiples filas - RAW Laravel SQL

Actualizar mysql o insertar múltiples filas - RAW Laravel SQL

Problema

Tengo mensajes en el sistema enviado entre varias personas como chat grupal. Cada vez que alguien va a cargar mensajes (abre su bandeja de entrada), necesito que esos mensajes se marquen como leídos. No tengo un modelo elocuente para la tabla Pivot direct_message_read_at, y estoy usando una clase que encapsula la clase DB Laravel para escribir una consulta MySQL personalizada para hacer esto.

Mi problema es, ¿cómo evito las entradas duplicadas si alguien abre el hilo del mensaje 10 veces y hago el cambio de marca de tiempo actualizado_at cada vez que lean el mensaje?? (Dado que abrirán el mismo hilo de mensaje varias veces)

Solución

Para ayudar con la configuración de esta solución, primero mostremos cómo creamos esta tabla usando la migración de Laravel:

Antes del pivote, crearíamos una tabla de mensajes para almacenar todos los mensajes de las personas. Después de eso creamos la tabla de pivote.

Schema :: create ('direct_message_read_at', function (blueprint $ table)
$ table-> incrementos ('id');
$ table-> integer ('message_id')-> unsigned ()-> nullable ();
$ table-> extranjero ('mensajes_id')-> referencias ('id')-> on ('direct_messages')-> onDelete ('cascade');
$ table-> integer ('user_id')-> unsigned ()-> nullable ();
$ table-> extranjero ('user_id')-> referencias ('id')-> on ('usuarios')-> onDelete ('cascade');
$ table-> integer ('organización_id')-> unsigned ()-> nullable ();
$ table-> extranjero ('organización_id')-> referencias ('id')-> on ('organizaciones')-> onDelete ('cascade');
$ table-> timestamps ();
$ table-> único (['Message_id', 'user_id', 'organización_id']); // Esto es realmente importante para
evitar entradas duplicadas de la misma persona
);

Ahora, queremos crear un evento y un oyente que procese los mensajes cargados.

Imagine que tiene una clase responsable de cargar todos sus mensajes (cuando abre su bandeja de entrada)

función pública LoadMessages ()

$ thread_messages = directMessage :: all ();
$ Message_ids = $ this-> removemyMessages ($ thread_messages)
evento (nuevo MessagesRead ($ Messages_IDS));

función protegida removemyMessages ($ mensajes)

$ Message_ids = [];
// Simplemente filtre todos los mensajes que usted envía utilizando 'Where (' Sender_id ',
auth ()-> user ()-> id)-use su propia lógica de código para hacerlo
devolver $ mensaje_ids;

Ahora dentro de los mensajes Read, puede definirlos y pasarlos al oyente

Mensajes de clase Reading

Use despachable, interactswithsockets, SerializeModels;
public $ Messages_ids = [], $ user_id, $ organización_id;
/**
* Crear una nueva instancia de evento.
*
* @return void
*/
función pública __construct ($ message_ids = [])

$ this-> Messages_ids = $ Message_ids;
$ this-> user_id = auth ()-> user ()-> id;
$ this-> organización_id = auth ()-> user ()-> organización_id;

/**
* Obtenga los canales en los que debe transmitirse el evento.
*
* @return \ iluminate \ broadcasting \ canal | Array
*/
Función pública Broadcaston ()

devolver nuevo privateChannel ('Channel-Name');

Dentro del oyente que definió previamente en EventserviceProvider, puede llamar a su clase para procesar la actualización de la tabla de pivote

clase MarkMessagesAsread

/**
* Crea el oyente del evento.
*
* @return void
*/
función pública __construct ()

//

/**
* Manejar el evento.
*
* @param MessagesRead $ Evento
* @return void
*/
Mango de la función pública (evento MessageRead $)

$ Message_ids = $ Event-> Messages_ids;
$ user_id = $ event-> user_id;
$ organización_id = $ event-> organización_id;
(New CreateIrectMessageRindicator (nuevo DB))-> Ejecutar ($ Message_ids, $ user_id,
$ organización_id);

Y finalmente, nos estamos acercando al final. Todo lo que tenemos que hacer ahora es mirar realmente la consulta MySQL

clase creada directMessageRindicator

protegido $ dB;
función __construct (db $ db)

$ this-> db = $ db;

/**
* Construya y devuelve la cláusula de selección para la consulta
*
* @return cadena
*/
Función pública Ejecutar ($ Message_ids = [], $ user_id, $ organización_id)

if (Count ($ Message_ids) <= 0)
falso retorno;

$ create_at = date ('y-m-d h: i: s');
$ actualizado_at = date ('y-m-d h: i: s');
$ parámetros = [];
foreach ($ mensaje_ids como $ mensaje_id)
array_push ($ parámetros, "($ mensaje_id, $ user_id, $ organización_id,
'$ create_at') ");

$ parámetros_string = implose (",", $ parámetros);
$ query = "
Insertar en direct_message_read_at (message_id, user_id, organización_id,
Creado en)
VALORES
$ parámetros_string
En la clave duplicada actualización actualizada_at = "$ updated_at";
";
$ this-> db :: select ($ consulta);

Entonces, ¿qué acabo de pasar aquí?. Básicamente marcamos Message_ID, User_id y Organization_ID como la combinación única. En caso de que el mismo user_id que pertenece a la misma organización organización_id abre el mismo mensaje de alguien que tiene ese mensaje_id, lanzará un error de duplicación de MySQL.

Cuando inserta una nueva fila en una tabla si la fila causa un duplicado en un índice único o clave primaria, MySQL emitirá un error.

Sin embargo, si especifica la opción de actualización de la tecla Duplicate en la instrucción Insertar, MySQL actualizará la fila existente con los nuevos valores en su lugar.

https: // www.mysqltutorial.org/mysql-insert o actual
Déjame compartir algunas capturas de pantalla.

El primer mensaje que se lee:

Insertar en direct_message_read_at (message_id, user_id, organización_id, creating_at)
VALORES
(75, 3, 1, '2020-01-16 15:00:00')
En la actualización de la clave duplicada actualizada_at = "2020-01-17 22:00:00"

Producirá esta entrada en la base de datos:

Luego regresa y lee el mismo mensaje mañana, hará que solo se actualice la columna actualizada_at:

De esta manera, sabes cuándo se vio el mensaje por primera vez, y cuándo fue la última vez que se leyó el mensaje.