Doctrine QueryBuilder按字段优先级排序结果

时间:2017-03-23 10:41:35

标签: php mysql symfony doctrine-orm

我的Service实体包含titletagsdescription字段。使用QueryBuilder搜索服务时,如何按字段优先级排序结果。例如,当我搜索字词php时,我希望在列表顶部的标题中获得php的服务,然后在其标记和服务中使用php的服务,其中包含搜索字词描述为最后一个。

这是我的Querybuilder的一部分:

    $qb = $this->createQueryBuilder('service');
    $qb->leftJoin('service.tags', 'tag');

    $conditions = array($conditions[] = $qb->expr()->eq('service.enabled', true));
    $conditions[] = $qb->expr()->eq('service.category', $categoryId);
    $term = '%' . $term . '%';
    $conditions[] = $qb->expr()->orX(
            $qb->expr()->like('service.title', "'$term'"),
            $qb->expr()->like('service.description',  "'$term'"),
            $qb->expr()->like('tag.name', "'$term'")
        );

    $conditions = call_user_func_array(array($qb->expr(), 'andX'), $conditions);

    $qb->where($conditions);

3 个答案:

答案 0 :(得分:4)

执行此操作的最佳方法是执行一系列UNION语句,然后在给出重量的同时清除重复项。

(未经检查的伪SQL提供了这个想法):

SELECT id,title,tag,SUM(weight) score
FROM (
   SELECT id,title,tag, 100 as weight FROM service WHERE title LIKE '%foo%'
   UNION ALL
   SELECT id,title,tag, 10 as weight FROM service WHERE tags LIKE '%foo%'
   UNION ALL
   SELECT id,title,tag, 1 as weight FROM service WHERE description LIKE '%foo%'
) t
GROUP BY id
ORDER BY score DESC /* This sort by probably won't work; might need to do it a different way, but you get the idea */

答案 1 :(得分:2)

您可以使用本机查询。例:

    $em = $this->get('doctrine')->getManager();

    $sql = "
        select *
        from service s
        where
            s.title like '%xxx%'
            or s.tags like '%xxx%'
            or s.description  like '%xxx%'
        order by 
            s.title like '%xxx%' desc,
            s.tags like '%xxx%' desc,
            s.description  like '%xxx%' desc
    ";

    $rsm = new \Doctrine\ORM\Query\ResultSetMappingBuilder($em);
    $rsm->addRootEntityFromClassMetadata('\You\Entity\Service\Class', 's');

    $query = $em->createNativeQuery($sql, $rsm);

    $data = $query->getResult();

    dump($data);

http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/native-sql.html如何在orm

中使用dql的sql

答案 2 :(得分:1)

不会尝试在只有一个查询中获得所需的结果。它太复杂了,你花了很多时间尝试得到你想要的东西。

首先,我假设您希望获得{em>排序数组的lme4实体,如下所示:

Service

所以你可以简单地通过它迭代(foreach)

如果是这种情况,请遵循以下标准:

  • 在您的服务存储库中创建三个单独的方法来获取
    1. 标题中包含搜索条件的服务 - 第一优先级
    2. 在其代码中使用搜索条件的服务 - 第二优先级
    3. 服务中包含serach标准的desc - 第三优先级

并且在您的/** @var Service[] $results **/ $results = $this->getDoctrine()->getManager()->getRepository('YourBundle:YourServiceRepo')->findSerivesByGivenSerchCriteria($yourConditions); 方法中,您可以调用其中的所有三个,并且可以按照我喜欢的任何顺序合并找到的结果

例如:

findSerivesByGivenSearchCriteria()

获得" uniqness"尝试结合Doctrine的public function findSerivesByGivenSerchCriteria( $searchTirm ) { $foundServicesByTitle = $this->findServicesBySearchCriteriaInTitle( $searachTirm ); $foundServicesByTag = $this->findServicesBySearchCriteriaInTags( $searchTirm ); $foundServicesByDesc = $this->findServicesBySearchCriteriaInDesc( $searchTirm ); // Hier you can combine found results in any order $results = []; if( false === empty($foundServicesByTitle ) ) { // for example with array_merge ... // NOTE: If you choose array_merge() you have to make sure your $foundServicesByTitle, $foundServicesByTag, $foundServicesByDesc have unique array-indexes // And you get Results like // array( 'unique_id_1' => ServiceEntity, 'unique_id_2' => ServiceEntity ... ) $results = array_merge($results, $foundServicesByTitle); } // .. do the same with other two return $results; } INDEX BY

HIDDEN - > http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/dql-doctrine-query-language.html#using-index-by

QueryBuilder中的

INDEX BY - > https://stackoverflow.com/a/15120793/348193

INDEX BY - > https://michelsalib.com/2012/03/04/doctrine2-ninja-with-the-hidden-keyword/

为什么我不会选择HIDDEN方式?

因为你使用symfony和doctrine UNION并不是最好的方法。见How to write UNION in Doctrine 2.0

正如您所看到的,UNION 不受Doctrine 支持,您必须使用UNION(这可能会让NativeQuery感到沮丧核心映射并将原始结果转换为所需的实体)