2011-03-20 2 views
2

Прежде чем вы начнете кричать ORDER BY id, ситуация совсем иная.Упорядочить посты форума по времени последнего ответа

Форум, на котором меня просили сделать, - это форум гостевой книги, на котором незарегистрированные пользователи могут отвечать и делать сообщения. Ответы на сообщение отступы под сообщением, на который отвечает. Конечно, все это в неупорядоченных списках. Краткий пример:

  • Основное сообщение
    • Ответить на сообщение
      • Ответ на ответ
    • Другой ответ на главный
  • пост, который не имеет ничего общего с ответами

Это вроде того, что система комментариев Nettuts+ «s выглядит. В базе данных сообщение имеет все очевидные вещи (id, тело сообщения, автор, время ...) и ответ. Ответ в основном означает, на что ответит этот пост. Если answerid равно 0, это главный пост (поток в обычном форуме означает).

Вот как я обхожусь вокруг отображения этих сообщений: сначала я вызываю функцию (назовем ее showPosts), которая имеет необязательный параметр, называемый replyid; по умолчанию - 0.

В showPosts Я захватываю все сообщения с ответом, равным параметру из базы данных в ассоциативном массиве, и заполняю поле posts в массиве с результатами showPosts, и я передаю showPosts идентификатор почты. В конце showPosts я возвращаю этот ассоциативный массив. Если бы это было неясно, вот фрагмент кода:

function showPosts($postid = 0) { 
     $query = query("SELECT * FROM posts WHERE replyid='$postid'"); 
     $r = array(); 
     $i = 0; 
     while (@$row = $query->fetch_assoc()) { 
      $r[$i] = $row; 
      $r[$i]['posts'] = showPosts($row['id']); 
      ++$i; 
     } 
     return $r; 
    } 

Все работает прекрасно, как и следовало ожидать, но я топал по этой проблеме: Когда пользователь отвечает на старый пост, я хочу этот пост, чтобы показать первый, так же, как у вас есть в форумах.

Я уже думал о создании поля в базе данных, называемом lastChanged, и всякий раз, когда пользователь отправляет новый ответ, он продвигается вверх по цепочке сообщений и изменяет каждое из своих значений lastChanged на время публикации. Однако это казалось просто пустой тратой памяти и возможным убийцей времени. Я также думал о разделении основных потоков от ответов, но это сделало бы вещи немного более сложными на уме, и мне нравится красота, не имеющая значения между нитью и сообщением, поскольку все может быть либо потоком или должность.

Только так вы знаете, база данных MySQL и бэкенд написана в PHP (и, конечно, взаимодействие с MySQL с помощью MySQLi.)

Заранее спасибо, и извините, если что-то неясно.

Редактировать: Структура db, как и требовалось.

id  | int(11) 
title | varchar(100) 
author | varchar(100) 
body | text 
replyid | int(11) 
time | datetime 
+0

Прежде чем кричать «прежде чем вы кричите», вы должны разместить здесь таблицу (ы) структуры. это тривиальный список смежности или что? –

+0

Идея 'lastChanged' была тем, что я собирался предложить - когда вы говорите, что это пустая трата памяти или убийца времени, что вы имеете в виду? Если этот столбец для 'ORDER BY' звучит как время для меня, вместо того, чтобы вычислять, какой порядок сообщений должен быть каждый раз. –

+0

@Sam Starling - Когда я убил время, я имел в виду, что каждый раз, когда пользователь сохраняет сообщение, вам нужно будет подобрать цепочку ответов на вершину и на каждом шаге обновить поле. Позже это экономия времени, но я немного обеспокоен первоначальным исполнением. – Zirak

ответ

0

Если вы не хотите идти с lastChanged

Вы должны вычислить последнее время последнего комментария в секции дисплея (в методе PHP вы публикуемую), и когда у вас есть для родительский пост с последней измененной датой, вы можете сделать сортировку в массиве php.

Эта прогулка не будет чем-либо в плюсе, поскольку у вас уже есть рекурсия, вам просто нужно выяснить, как правильно подобрать дату последнего ответа и отсортировать массив до окончательного возвращения.

Нечто подобное (без вида)

function getPost($postid = 0) { 
     $query = query("SELECT * FROM posts WHERE replyid='$postid'"); 
     $r = array(); 
     $i = 0; 
     $recenttime=0; 
     while (@$row = $query->fetch_array(MYSQLI_ASSOC)) { 
      $r[$i] = $row; 
      if (strtotime($row['time'])>$recenttime) { 
       $recenttime=strtotime($row['time']); 
      } 
      $r[$i]['posts'] = $this->getPost($row['id']); 
      if ($r[$i]['posts']['recenttime']>$recenttime) { 
       $recenttime=$r[$i]['posts']['recenttime']; 
      } 
      ++$i; 
     } 
     $r['recenttime']=$recenttime;//save recenttime for this level 
     if ($postid == 0) { 
      // do the sort here based on $r[$i][$recenttime]; 
     } 
     return $r; 
} 
+0

У меня было аналогичное решение в виду и посмотрел на [array_walk_recursive] (http://php.net/array-walk-recursive), но после нескольких попыток сделать это я взволновался и полностью потерпел неудачу. У вас есть какое-либо направление или совет, чтобы начать писать то, что вы предложили? – Zirak

+0

Вам не нужно ходить по массиву, вам просто нужно вернуть последние даты из нижней части рекурсии. – Pentium10

0

Учитывая комментарии в оригинальный вопрос между собой и Zirak, я предлагаю следующий ответ.

Он прав - обход всего дерева, чтобы найти дату последнего комментария, может занять некоторое время, поскольку, как кажется, нет ограничений на количество уровней вложенности, которые могут иметь место в системе. Я знаю, что это много повторений данных, но почему бы не хранить что-то вроде main_post_id, которое относится к корневому узлу (основному сообщению). Таким образом вы можете ORDER BY max(time) WHERE main_post_id = 1.

Если это программное обеспечение для форума (поэтому я предполагаю, что поэтому может также включать такие вещи, как разбиение списков списков потоков), это облегчит жизнь, поскольку вы можете выполнять сортировку на уровне запросов к базе данных, а не в PHP.

0

Хм .. считая, что чтение списка выполняется гораздо чаще, чем написание. А также учитывая, что чтение включает гораздо больше данных, я бы предпочел поставить нагрузку на время записи.

С решением lastChanged на уровне root вы также можете сделать список с чтением гораздо меньше строк с помощью простого SQL-запроса вместо чтения x чисел строк.

Решение Sams имеет тот недостаток, что вам нужна дополнительная GROUP BY, что приводит к временной таблице, которая замедляет работу вашего сервера sql.

Смежные вопросы