web-dev-qa-db-fra.com

Comment interroger les utilisateurs qui ont toutes les balises lors de la recherche de plusieurs balises?

J'ai ce module personnalisé qui montre tous les contacts en fonction de certaines balises. Je peux ajouter une ou plusieurs balises dans un champ du module

Ce que je veux, c'est ajouter l'option dans le module pour montrer:

  1. tous les contacts qui ont TOUTES les balises spécifiées dans le module

ou

  1. tous les contacts qui ont une ou plusieurs étiquettes comme spécifié dans le module

Le code que j'ai vient de faire ce dernier. Comment puis-je ajouter la possibilité pour l'option 1?

Le code que j'ai est:

public static function getPeopleByTags($params)
{
  //echo "<pre>";
  $tags = $params->get("tags");

  $model = JModelLegacy::getInstance('Field', 'FieldsModel', array('ignore_request' => true)); //load fields model

  //get people info from database
  $db = JFactory::getDbo();
  $query = $db->getQuery(true);
  $query->select('id,catid,name,alias,image,email_to,published,user_id,tags.tag_id');
  //$query->select('*');

  $query->from($db->quoteName('#__contact_details').'AS contacts');
  $query->join('right','#__contentitem_tag_map AS tags ON `tags`.`content_item_id` = `contacts`.`id`');
  $query->where($db->quoteName("published") ." = 1  AND `tags`.`type_id` = 2 AND `tags`.`tag_id` IN (".implode(',',$tags).") ");
  $query->group('`contacts`.`id`');
  $db->setQuery($query);
  $people = $db->loadObjectList();

  return $people;

}

Joomla 3.9.0

2
Clements Radenborg

Tags - Similar module utilise la clause HAVING pour y parvenir.

$query->having('COUNT(' . $db->quoteName('tags.tag_id') . ') = ' . count($tags));

Mais je ne suis pas sûr que ce soit la meilleure solution possible. Cela pourrait être plutôt lent parce que WHERE IN sélectionne toutes les lignes correspondant à n’importe quelle balise et HAVING filtre uniquement après que les lignes ont été sélectionnées.

3
Sharky

J'ai pris le temps de configurer mes propres données de test et Sharky a raison (+1 à Sharky) concernant la mise en œuvre d'une clause HAVING.

$tag_ids = $params->get("tags");
$db = JFactory::getDbo();
$query = $db->getQuery(true)
    ->select("id, catid, name, alias, image, email_to, published, user_id")
    ->select(" GROUP_CONCAT(tags.tag_id) AS tag_ids")
    ->from("#__contact_details AS contacts")
    ->innerJoin("#__contentitem_tag_map AS tags ON tags.content_item_id = contacts.id")
    ->where("published = 1")
    ->where("type_id = 2")
    ->where("tag_id IN (" . implode(',', $tag_ids) . ")")
    ->group("contacts.id")
    ->having("COUNT(*) = " . sizeof($tag_ids));

echo $query->dump();
$db->setQuery($query);
echo "<pre>";
var_export($db->loadObjectList());

Sortie:

SELECT id, catid, name, alias, image, email_to, published, user_id, GROUP_CONCAT(tags.tag_id) AS tag_ids
FROM zyxwv_contact_details AS contacts
INNER JOIN zyxwv_contentitem_tag_map AS tags ON tags.content_item_id = contacts.id
WHERE published = 1 AND type_id = 2 AND tag_id IN (9,10)
GROUP BY contacts.id
HAVING COUNT(*) = 2
array (
  0 => 
  stdClass::__set_state(array(
     'id' => '12',
     'catid' => '21',
     'name' => 'Sharky',
     'alias' => 'sharky',
     'image' => 'images/sharky.jpg',
     'email_to' => '',
     'published' => '1',
     'user_id' => '0',
     'tag_ids' => '9,10',
  )),
  1 => 
  stdClass::__set_state(array(
     'id' => '82',
     'catid' => '21',
     'name' => 'mickmackusa',
     'alias' => 'mickmackusa',
     'image' => '',
     'email_to' => '',
     'published' => '1',
     'user_id' => '0',
     'tag_ids' => '9,10',
  )),
)
  • Pour afficher tous les tag_ids du jeu de résultats, utilisez GROUP_CONCAT() dans la clause SELECT.
  • Je préfère la logique d'utilisation d'INNER JOIN à RIGHT JOIN, mais je ne sais pas comment ils se comparent en termes de performances.
  • La clause HAVING peut utiliser COUNT(*) pour obtenir le même résultat que le chargement de la colonne tag_id.

Changer le numéro qui suit COUNT() dictera le nombre de balises qualifiantes requises pour qu'un contact/utilisateur soit inclus dans le jeu de résultats. Par exemple, si vous recherchez 3 balises différentes, mais n'en exigez que 2, vous obtiendrez toutes les lignes dans lesquelles les contacts/utilisateurs ont 2 balises qualifiantes sur 3.

1
mickmackusa