0

Je construis une interface de recherche qui cherche des commentaires. Lorsqu'un utilisateur clique sur un résultat de recherche (commentaire), je souhaite afficher les commentaires environnants.Comment obtenir des enregistrements basés sur un décalage autour d'un enregistrement particulier?

Mon modèle:

Group (id, title) - A Group has many comments 
Comment (id, group_id, content) 

Par exemple:

Lorsqu'un utilisateur clique sur un commentaire avec comment.id égal à 26. Je voudrais tout d'abord trouver tous les commentaires de ce groupe:

comment = Comment.find(26) 
comments = Comment.where(:group_id => comment.group_id) 

J'ai maintenant tous les commentaires du groupe. Ce que je veux ensuite faire est de montrer comment.id 26, avec un maximum de 10 commentaires avant et 10 commentaires après.

Comment puis-je modifier les commentaires pour afficher ce décalage?

Répondre

0

Quelque chose comme:

comment = Comment.find(26) 
before_comments = Comment. 
    where('created_at <= ?', comment.created_at). 
    where('id != ?', comment.id). 
    where(group_id: comment.group_id). 
    order('created_at DESC').limit(10) 
after_comments = Comment. 
    where('created_at >= ?', comment.created_at). 
    where('id != ?', comment.id). 
    where(group_id: comment.group_id). 
    order('created_at DESC').limit(10) 
+0

Comment faites-vous sûr d'obtenir que les commentaires dans la group_id correcte? – AnApprentice

+0

J'étais curieux de savoir si c'était possible w une requête contre plusieurs? – AnApprentice

+0

Vous pouvez probablement écrire une requête SQL complexe qui va faire tout ce qui précède en un seul coup, mais il va souffrir de la lisibilité. – gylaz

2

Cela paraît simple, mais il est difficile d'obtenir la meilleure performance pour cela. Dans tous les cas, vous devez laisser la base de données faire le travail. Cela sera plus rapide d'un ordre de grandeur que l'extraction de toutes les lignes et le filtrage/tri du côté client.

Si par « avant » et « après » vous signifie plus petit/plus comment.id, et nous supposons en outre qu'il peut y avoir des lacunes dans l'espace id, ce une requête doit faire tout:

WITH x AS (SELECT id, group_id FROM comment WHERE id = 26) -- enter value once 
(
SELECT * 
FROM x 
JOIN comment c USING (group_id) 
WHERE c.id > x.id 
ORDER BY c.id 
LIMIT 10 
) 
UNION ALL 
(
SELECT * 
FROM x 
JOIN comment c USING (group_id) 
WHERE c.id < x.id 
ORDER BY c.id DESC 
LIMIT 10 
) 

Je vais paraphraser cela en syntaxe Ruby, ce n'est pas mon domaine d'expertise.

Renvoie 10 commentaires précédents et 10 derniers. Moins si moins existent. Utilisez <= dans la deuxième étape de la requête UNION ALL pour inclure le commentaire sélectionné lui-même.

Si vous avez besoin de trier les lignes, ajoutez un autre niveau de requête avec ORDER BY.

devrait être très rapide en combinaison avec ces deux indices pour la table comment:

  • un sur (id) - probablement couverts automatiquement la clé primaire.
  • un sur (group_id, id)

Pour données en lecture seule, vous pouvez créer une vue matérialisée par une rangée numéro d'écart-moins qui rendrait ce encore plus vite.

More explanation about parenthesis, indexes, and performance in this closely related answer.

Questions connexes