2

Using symfony2 but its more just mysql problem...

I think i have good table schema(just the important fields)(code is self explanatory):

users (id) statuses (id) likes (id,user_id,status_id) comments (id,user_id,status_id)

I am making big select.

Was trying this:

    $qb=$this->createQueryBuilder('s')
             ->addSelect('u')
             ->addSelect('u2')
             ->addSelect('u3')
             ->addSelect('l')
             ->addSelect('c')
             ->addSelect('s2')
             ->where('s.user = :user')
             ->setParameter('user', $user)
             ->innerJoin('s.user', 'u')
             ->leftJoin('s.likes', 'l')
             ->leftJoin('l.user', 'u2')
             ->leftJoin('s.comments', 'c')
             ->leftJoin('c.user', 'u3')
             ->leftJoin('c.status', 's2')
             ->orderBy('s.time', 'DESC')
             ->setMaxResults(15);

But the result is 15the same statuses... WRONG.

It worked well when i was selecting just statuses... likes to statuses.. and users(authors of likes and statuses)

Like that:

SELECT * FROM statuses s0_ 
INNER JOIN users t1_ ON s0_.user_id = t1_.id 
LEFT JOIN status_likes s2_ ON s0_.id = s2_.status_id
INNER JOIN users t3_ ON s2_.user_id = t3_.id  

WHERE s0_.user_id = 25 ORDER BY s0_.time DESC LIMIT 15

that works very nice but how can i implement the another comments and (users -> authors of comments) select THERE?...

Lukas Lukac
  • 7,766
  • 10
  • 65
  • 75

1 Answers1

1

You can't set max results on a joined query in the way you are attempting.

You need to use the paginator as described here: http://docs.doctrine-project.org/en/latest/tutorials/pagination.html

If it's not available in your version of Doctrine (you are pre 2.2) Then you can use the paginator here: https://github.com/beberlei/DoctrineExtensions

Another option is to not perform the join in the query - but simply allow the joined data to be fetched automatically. So iterate over users and traverse the object graph to get the infomation you require. This will obviously issue far more queries:

$users = $userRepository->findById($user);
$i = 0;
for ($users as $user){
    $likes = $user->getLikes(); 
    $comments = $user->getComments();
    $i++;
    if ($i == 15) { break; }
}

edit: changed the 'continue' to a 'break'; This is crappy code anyway - don't use it, I'm just illustrating an alternative.

Finally you could use a native query to perform this:

http://docs.doctrine-project.org/en/2.1/reference/native-sql.html

Edit: Similar question: Limiting a doctrine query with a fetch-joined collection?

Community
  • 1
  • 1
calumbrodie
  • 4,722
  • 5
  • 35
  • 63
  • First time hearing about pagination ... i am 2.2.3 i think .. and i need to do it with as less query as posiblle and with the best performances...i have my query in own repository and as i looked at your pagination link... i am prety confused whats going on..(2AM) could you please show me my situation more friendly example with little be explanation or it would be too much work? BTW: when i REMOVED from my query THE LIMIT statement, i get all statuses... BUT each status is returned abou 30times??? doesn't seems to be very good wroten... or? – Lukas Lukac Mar 29 '13 at 00:56
  • Did you try the code at the top of the pagination documentation? I suspect you might be trying to use DQL like SQL and it's not the same thing. You can get the same object $query, in the example by pulling a query from your query builder like this. $qb->getQuery(); Feed that into the Paginator as per the example and see if that helps. – calumbrodie Mar 29 '13 at 01:57
  • thx! hmm the pagination seems to be working. But when i try count($paginator) i see there: 50. What does it means? + what do you say on so much same returned rows when i was trying just SQL in phpmyadmin ?? (question from comment first). To info like id of status... now i accessing by $status->getId() and no $status['id'] ( i had getArrayResult in query before) ... but thats ok seems to be working i am just not sure about performances now?? from 13ms i have 260ms!! first query select distinct id of statuses. and second is selecting all data from these ids. HM??? – Lukas Lukac Mar 29 '13 at 12:18
  • @Trki that's how pagination works. Since you cannot trust the number of results because of fetch-joined results, you first need to select the identifiers of the root entity (distinct), then use an `IN()` clause to match only a subset of those in a second result. – Ocramius Mar 29 '13 at 12:58
  • hm... but so many queries? so much time?? 250ms is a lot i think.. isnt?? all queries are just 2ms or like that.. and now this? Hm... is that as best as it can be? have i wrote my select good? please check it carefully. – Lukas Lukac Mar 29 '13 at 13:20
  • @Trki that's the only way to handle it as far as I know. You should probably profile it DB-side and PHP-side and see where the bottleneck is. – Ocramius Mar 30 '13 at 09:24
  • hm.. i am sorry how you meaned it? in php side is ok.. the problem is at DB site 250ms is loading of queries... script is in my question. – Lukas Lukac Mar 30 '13 at 09:32
  • There should be 3 queries - and then one additional query for each 'page' of data you are accessing. And yes 250ms seems large, but without any context (size of database, type of fields, keys used etc) it's impossible for us to guess what is wrong. – calumbrodie Mar 31 '13 at 14:36