Helpex - Trao đổi & giúp đỡ Đăng nhập
4

Các bảng của tôi được cấu trúc như sau:

TAGS (nhiều loại hơn): id, tên thẻ, mô tả, slug

BÀI ĐĂNG: id, tiêu đề, url ...

POSTSTAGS: id, idPost, idTag

NGƯỜI DÙNG: id, tên người dùng, userSlug ...

VOTES: id, idPost, idUser

Mỗi bài đăng có thể có tối đa năm thẻ và mỗi người dùng chỉ có thể bỏ phiếu một lần. Hiện tại, vì các thẻ chưa được triển khai, tôi truy xuất tập hợp kết quả được phân trang của mình bằng truy vấn sau:

SELECT p.*, u.username, u.userSlug, u.id as userId, 
exists (select 1 from votes v where v.idUser=$id AND p.userId=v.idUser AND p.url = v.url) as voted 
FROM posts p 
JOIN users u ON u.id=p.userId
ORDER BY p.created DESC
LIMIT 10 OFFSET :offset

Truy vấn được chạy qua PDO và được trả về ở định dạng JSON thành một anglejs ng-repeat. Đây $idlà id của người dùng đã đăng nhập. Tôi sử dụng nó trong existstruy vấn con để làm xám các nút bỏ phiếu trong chế độ xem góc cạnh của tôi (cũng có kiểm tra ở phía máy chủ). Nếu ai đó nhấp vào tên người dùng trong chế độ xem, anh ta sẽ được đưa đến trang chi tiết nơi tất cả các bài đăng của người dùng được hiển thị ( userSlugđể giải cứu).

Bước tiếp theo là đưa các thẻ vào danh sách kết quả và ở đây tôi đã nói lắp. Mỗi bài đăng trong danh sách phải chứa tất cả các thẻ được liên kết (tagName, description, slug) và mỗi thẻ phải đưa bạn đến trang chi tiết nơi tất cả các bài đăng được liên kết cho thẻ cụ thể đó được hiển thị.

Giải pháp đầu tiên tôi nghĩ đến là thực hiện theo cách của tôi để giải quyết vấn đề này sau khi chạy truy vấn đã đề cập trước đó:

foreach ($postsResult as &$post) {
    $sql ="SELECT t.* FROM tags t JOIN poststags pt ON t.id=pt.idTag WHERE pt.idPost=$post->id";
    $stmt=$db->prepare($sql);
    $stmt->execute();
    $tagsResult=$stmt->fetchAll(PDO::FETCH_OBJ);
    $post->tags = $tagsResult;
}
$response->write(json_encode($postsResult));

Xong, dễ dàng! Rất nhiều truy vấn sẽ tạo ra một lượng lớn sự căng thẳng trên máy chủ. Và chúng tôi không muốn làm điều đó.

Giải pháp thứ hai là kích hoạt một truy vấn khác tìm nạp tất cả các thẻ được liên kết với (các) postsResult và sau đó chèn các thẻ tương ứng vào mỗi bài đăng để PHP thực hiện công việc bẩn thỉu.

$sql = "
    SELECT t.*, 
           pt.idPost 
      FROM tags t JOIN poststags pt ON t.id=pt.idTag 
     WHERE pt.idPost IN (array of post ids)
";
$stmt=$db->prepare($sql);
$stmt->execute();
$tagsResult = $stmt->fetchAll(PDO::FETCH_OBJ);

foreach ($postsResult as &$post) {
    $arr = array();

    foreach ($tagsResult as $tag) {
        if ($post->id==$tag->idPost) {
            $arr[]=$tag;
        }
    }

    $post->tags = $arr;
}
$response->write(json_encode($postsResult));

Có cách nào tốt hơn hoặc nhanh hơn để làm điều này không?

4 hữu ích 0 bình luận 366 xem chia sẻ
3

Có cách nào tốt hơn hoặc nhanh hơn để làm điều này không?

Nếu bạn lập chỉ mục $tagsResulttheo postId, mà bạn có thể thực hiện bằng cách sử dụng FETCH_GROUP, thì bạn có thể loại bỏ vòng lặp lồng nhau bên trong và lấy tất cả các thẻ với một postId nhất định trong thời gian không đổi:

$sql = "
    SELECT pt.idPost, — select idPost first so it’s grouped by this col
           t.*
      FROM tags t JOIN poststags pt ON t.id=pt.idTag 
     WHERE pt.idPost IN (array of post ids)
";

$stmt=$db->prepare($sql);
$stmt->execute();

$tagsResult = $smt->fetchAll(\PDO::FETCH_GROUP|\PDO::FETCH_OBJ);
//$tagsResult is now grouped by postId
//see https://stackoverflow.com/questions/5361716/is-there-a-way-to-fetch-associative-array-grouped-by-the-values-of-a-specified-c

foreach($postsResult as &$post) {

    if(isset($tagsResult[$post->id])) {
        $post->tags = $tagsResult[$post->id];
    }
    else {
        $post->tags = array();
    }   
}
3 hữu ích 1 bình luận chia sẻ
loading
Không tìm thấy câu trả lời bạn tìm kiếm? Duyệt qua các câu hỏi được gắn thẻ php mysql sql angularjs , hoặc hỏi câu hỏi của bạn.

Có thể bạn quan tâm

loading