Estoy construyendo un sistema de respuesta de comentarios anidados dentro de mi aplicación.Cómo combinar estas consultas MySQL y luego acceder a los datos correctamente
Actualmente todo funciona según lo previsto, sin embargo, he tenido que usar varias consultas MySQL para recuperar los datos necesarios. Y lo que es peor, la consulta para las 'respuestas' está dentro de un ciclo foreach. Lo que significa que, aunque funciona de manera admirable por ahora, está lejos de ser óptimo y causará problemas a medida que crezca el conjunto de datos.
Por lo tanto, deseo resolver esto antes de profundizar en el desarrollo.
Dado que las tablas de la aplicación comparten lo mismo que el blog de wordpress para el sitio, estoy usando la abreviatura de wordpress para las consultas.
La forma actual se genera la página es el siguiente:
Una mesa de comentarios se consulta y todos los resultados relativos a un projectId se recuperan: -
$commentquery = "select projects_comments.*, users.user_url, users.display_name
from ".$wpdb->prefix."projects_comments projects_comments
left join ".$wpdb->prefix."users users on users.ID=projects_comments.userid
where projectid = '$projectid'
order by projects_comments.commentid desc
";
$comments = $wpdb->get_results($commentquery);
entonces realizar un bucle foreach de la siguiente : -
if($comments) {
foreach ($comments as $c)
{
$replyquery = "select project_replies.*, users.user_url, users.display_name
from ".$wpdb->prefix."project_replies project_replies
left join ".$wpdb->prefix."users users on users.ID=project_replies.uid
where project_replies.cid = '$c->commentid'
order by project_replies.id desc
limit 2
";
$replies = $wpdb->get_results($replyquery);
asort($replies);
$countquery = "select count(*)
from ".$wpdb->prefix."project_replies project_replies
where project_replies.cid='".$c->commentid."'
";
$replycount = $wpdb->get_var($countquery);
//generate html here
}
}
Dentro de este bucle hay otras dos consultas. El primero obtiene las respuestas para cada comentario pero limita los resultados a 2 (deseo hacer esto para tener un botón "ver todas las respuestas" que luego pregunta al DB por el resto si el usuario lo requiere), la segunda consulta cuenta el número total de respuestas.
El html es entonces también genera para cada respuesta dentro del bucle utilizando un segundo foreach anidado dentro del bucle anterior (donde dice generar código HTML aquí) como a continuación: -
if ($replies){
foreach ($replies as $r){
// generate each reply
}
}
Todos los datos se extrae de estas matrices de la siguiente manera:
$c->userid, $c->body etc... For the comments
$r->userid, $r->body etc... For the replies.
Deseo mantener este formato si es posible.
Como dije al principio de la pregunta, todo esto funciona a la perfección; sin embargo, soy consciente de que al anidar las consultas de conteo y conteo, realizo muchas más consultas de las necesarias. 100 comentarios generarán 100 consultas de respuestas y 100 consultas de conteos, etc.
Gracias a algunas personas útiles en este sitio, he considerado utilizar una unión para obtener todos los datos originales de una sola vez para los comentarios y respuestas. Al igual que ...
$commentquery2 = "SELECT c.commentid, c.userid, c.body as cbody, c.projectid, c.posttime, cu.user_url AS cu_url, cu.display_name AS cu_name,
r.*, ru.user_url AS ru_url, ru.display_name AS ru_name
FROM ".$wpdb->prefix."projects_comments AS c
LEFT JOIN ".$wpdb->prefix."users AS cu ON cu.ID = c.userid
LEFT JOIN ".$wpdb->prefix."project_replies AS r ON r.cid = c.commentid
LEFT JOIN ".$wpdb->prefix."users AS ru ON ru.ID = r.uid
WHERE c.projectid = $projectid
ORDER BY c.commentid DESC, r.id DESC";
Aunque esto en realidad funciona (y fue suficiente para mí para marcar esa pregunta como respondida), cuando se lo ponga en práctica he tenido varias dificultades.
Primero, recupero todos los datos como filas separadas, lo que significa que si tengo 5 comentarios cada uno con 3 respuestas, realmente obtengo 15 filas y no un objeto de datos anidado con las respuestas anidadas dentro de cada fila de comentario.
Para hacer frente a este he intentado alguna manipulación matriz como se muestra:
$old_id=NULL;
$comments=array();
foreach($getcomments as $c){
if($c->commentid !== $old_id){
$comments[$old_id] = $c;
$old_id = $c->commentid;
}
$comments[$old_id]['replies'][] = $c;
}
Hacer esto me da un objeto de datos anidada según sea necesario.Sin embargo, no incluye la consulta de recuento de respuestas y no limita cada conjunto de respuestas a 2 según lo previsto, sino que recupera todas.
Y, finalmente, con mi código html generación actual dentro de los foreach:
foreach($comments){
//generate comment html
foreach($replies) {
//generate replies html
}
}
Me parece que no puede conseguir que funcione correctamente con el objeto de datos anidada. Acceder a las respuestas correctas profundas parece desconcertarme.
Para resumir, deseo poder eliminar las consultas en bucle, combinarlas en una consulta grande y más eficiente o, en el peor de los casos, en una consulta de datos y una consulta de conteo separada, luego crear un objeto de datos cuidadosamente anidado. con los comentarios como filas y las respuestas anidadas dentro del encabezado 'respuestas'
Luego necesito poder iterar a través de estos correctamente dentro de mi código php para generar el html requerido.
Me disculpo por la longitud de esta pregunta y me doy cuenta de que bien podría dejar sin respuesta a muchos de ustedes, pero he estado batallando con esto durante 19 horas seguidas y realmente necesito la ayuda.
Muchas gracias a cualquiera que ofrezca alguna sugerencia.
Probablemente sólo añadir sus tablas con datos de ejemplo y la tabla resultante se están esperando para conseguir que debería haber sido más útil. –
Muy posiblemente Mosty, punto tomado. Si no tuviera tanta prisa ya que tengo una unidad de 2 horas antes de comenzar 10 minutos, podría editar la pregunta como sugirió. – gordyr
Esto ha sido cubierto varias veces, incluyendo este artículo: http://stackoverflow.com/questions/317322/optimized-sql-for-tree-structures – crafter