I have a query that joins several tables,
$qb = $dbm->createQueryBuilder();
$qb->select('job', 'tasks')
->from('MyJobBundle:Job', 'job')
->innerJoin('job.tasks', 'job_tasks');
This works as expected and I have an array of tasks for every job. I want to just count the number of tasks but not return them. Something like,
$qb = $dbm->createQueryBuilder();
$qb->select('job', 'count(job.tasks) as num_tasks')
->from('MyJobBundle:Job', 'job')
->innerJoin('job.tasks', 'job_tasks');
How can I do this?
Try this :
$qb->select('count(job_tasks) as num_tasks')
->from('MyJobBundle:Job', 'job')
->innerJoin('job.tasks', 'job_tasks')
->groupBy('job')
->getQuery()
->getResult();
That should return the counts for each job value
Related
I'm trying to fetch some data with a subquery using Eloquent but dding returns nothing. Separately, this
$discountArticles = $discountTableItemIdIn
->where('recipient_type', '=', 'article')
->toArray();
or this
$discountArticles = $discountTableItemIdIn
->where('recipient_id', '=', $articleId)
->toArray();
work fine.
However when I try something like this, it fails (or rather, returns nothing):
$discountArticles = $discountTableItemIdIn->where(function ($subQuery) {
$subQuery
->where('recipient_type', '=', 'article')
->where('recipient_id', '=', $articleId);
})->toArray();
I know I can do separate queries on the same collection and do an array_merge but I'd like to get this way working instead. Not sure what's happening.
So $discountTableItemIdIn is a collection of the entire table? That means you're gonna need a different function, as the ->where() logic on a collection is different from how it functions on a builder (eloquent) instance.
Try using filter():
$discountArticles = $discountTableItemIdIn->filter(function ($item) use($articleId) {
return $item->recipient_type == "article" && $item->recipient_id == $articleId;
})->toArray();
What this will do is filter your $discountTableItemIdIn collection for records that have a type of article and a recipient_id of whatever $articleId contains, return a new collection and convert that to an array.
Just a note, this is quite inefficient; you should try to avoid loading the whole table into a collection and just query the table directly using the subquery logic in your question.
I have a table called gk and I am currently running two queries. Please have a look at the queries:
Gk::groupBy(DB::raw("MONTH(created_at)"))
->groupBy(DB::raw("YEAR(created_at)"))
->selectRaw('id, user_id, sum(ton) as ton,pl, count(id) as total, sum(w) , created_at')
->with(array('user'=> function($q){
$q->select('id', 'userName', 'profilePic');
}))
->where('user_id', $userData[0]->id)
->get();
This query returns a little summary of every months. As you can I see I am grouping results by months and years. And I have another query which will return all the rows of any given months.
I am running second query like this
$m=Carbon::parse($request->date);
Gk::where('user_id',$request->user_id)->whereRaw(DB::raw("YEAR(created_at)=$m->year"))->whereRaw(DB::raw("MONTH(created_at)=$m->month"))
->orderBy('created_at','desc')
->get();
The second query returns all the rows of any month. I'm executing this query in a foreach loop for all of the months that are returned in the first query.
I am trying to combine this two query into one so that I can get a group of the results by months and years and also all the details of that month.
Any help, suggestions or idea would be extremely helpful.
[Note: For the date in second query, this date is created_at result from the first query.]
Thank you.
The way I read your question is as following: The second query is executed in a loop with results from the first one. Is that right? In my answer I have explained a way to execute the second query just one time instead of in a loop. You'd still have to execute the first query once.
So, I think that you are better of using the Php collection methods:
$results = Gk::where('user_id',$request->user_id)
->orderBy('created_at','desc')
->get()
->groupBy(function (Gk $item) {
return $item->created_at->format('Y-m');
});
The groupBy method has to return an attribute on which you want to group the elements. For this example I think that using a yyyy-mm format will do fine.
Reference: https://laravel.com/docs/5.5/collections#method-groupby
Edit: Maybe you can also get rid of the orderBy method call because you are grouping by afterwards:
$results = Gk::where('user_id',$request->user_id)
->get()
->groupBy(function (Gk $item) {
return $item->created_at->format('Y-m');
});
Edit 2: To combine the information of the two queries, you could do something like the following:
$results = Gk::where('user_id',$request->user_id)
->get()
->groupBy(function (Gk $item) {
return $item->created_at->format('Y-m');
})->map(function(Collection $rows) {
return [
'sum(ton)' => $rows->sum('ton'),
'total' => $rows->count(),
'sum(w)' => $rows->sum('w'),
'rows' => $rows
];
);
Note that I have omitted a few of the selected columns in your first query because they are not unique in the given group by. But feel free to add any logic in the map function. Because we use map() after groupBy, every call of map() will receive a collection of items for one month. You can that use that fabulous collection magic to calculate all values that you need and reduce the number of queries to just one.
In my symfony project I have two entities that are related via one to many.
I need to find the first and last child, so I use repository functions that look like this:
public function getFirstPost(Topic $topic)
{
$query = $this->createQueryBuilder('t')
->addSelect('p')
->join('t.posts', 'p')
->where('t.id = :topic_id')
->setParameter('topic_id' => $topic->getId())
->orderBy('p.id', 'ASC')
->setMaxResults(1)
->getQuery();
return $query->getOneOrNullResult();
}
public function getLastPost(Topic $topic)
{
$query = $this->createQueryBuilder('t')
->addSelect('p')
->join('t.posts', 'p')
->where('t.id = :topic_id')
->setParameter('topic_id' => $topic->getId())
->orderBy('p.id', 'DESC')
->setMaxResults(1)
->getQuery();
return $query->getOneOrNullResult();
}
So the only difference is in in ->orderBy(), for the first Post I use ASC and for the last I use DESC.
Now If I use one of those functions from my controller, the return the expected result and work just fine. But If I run them both at the same time from my controller, they return the same result, which they shouldn't.
My guess is that Doctrine caches these queries and the results somehow and that's why the return the same so I tried using $query->useResultCache(false) but that didn't do anything.
So my question is, why is this happening and how can I fix it?
Well, it is cache issue indeed, but mostly it is query issue. Instead of returning a post in these function you return the whole topic with joined posts.
What you can do is to rewrite these queries to select Post entity directly and join Topic entity to it which will be filtered by.
If you really(dont do this) need these queries to work you can detach first topic returned by one of those methods and then call the other method:
$this->getDoctrine()->getManager()->detach($firstTopic);
I have one MongoDb document with 3 fields message, author, sendAt, i have created a query builder to count all DB entries on this document and if there is more than 20 entries, I'm trying to delete the oldest one.
sendAt is the current dateTime when the message is send ("sendAt" : ISODate("2016-01-21T08:53:00Z"))
I have an unfinished query builder
public function deleteOldestMessage()
{
return $this->createQueryBuilder()
->delete('m')
->from('Messages', 'm')
->where('m.sendAt = ')
->execute();
}
But i really don't know what i should add on the where condition.
I should maybe order DESC the sendAt field and delete the first on the list ?
How can I tell the query builder to delete the oldest one ?
Thanks,
You need first to select the oldest one then you can delete it like this :
$qb->select('m')
->from('Messages', 'm')
->orderBy('m.sendAt', 'DESC');
$messages = $qb->getResult();
thene
if(count($messages) >= 20){
//get the first element of array which is the oldest one
$lastMessage = current($messages);
$em->remove($lastMessage);
}
You can try something like:
$qb = $em->createQueryBuilder();
$messages = $qb->select('m')
->from('Messages', 'm')
->orderBy('m.sendAt', 'ASC')
->getQuery()
->getResult()
;
// You will receive array where in the top will be the oldest message.
if (count($messages) > 20) {
// And in your desired case, you can remove just one oldest message.
$messageToDelete = array_shift($messages);
$em->remove($lastMessage);
$em->flush();
}
You use sql query builder options instead of mongodb.
return $this->createQueryBuilder()
->remove()
->sort('sendAt', 'asc')
->getQuery()
->getSingleResult()
->execute();
I have the following code in my Symfony2 Repository Class...
$query = $this->createQueryBuilder('foo')
->where('foo.bar = :id')
->setParameter('id', $myID)
->getQuery();
How do I get the number of rows found by the database?
Thanks in advance
You need to execute DQL to do something you want.
$query = $this->createQueryBuilder()
->from('foo', 'f')
->where('foo.bar = :id')
->setParameter('id', $myID)
->getQuery();
$total = $query->select('COUNT(f)')
->getQuery()
->getSingleScalarResult();
I think you can do something like that:
$query = $this->createQueryBuilder()
->select('COUNT(f.id)')
->from('foo', 'f')
->where('foo.bar = :id')
->setParameter('id', $myID)
->getQuery();
$total = $query->getSingleScalarResult();
You execute the query then get the results. When you have the results, you get the number of record by doing a count on the results:
$results = $query->getResult();
$resultCount = count($results);
If you are concerned with paging, like getting 25 records out of the total. Then, you have two choices.
You perform the query twice, one time to get total results, another time to retrieve only 25 results using the method setFirstResult and setMaxResults. This method setFirstResult enable you to set the offset and the second, setMaxResults, number of records. The following code will give you results ranging from 25 to 50, it's the second page if you use 25 records by page.
$query->setFirstResult(25);
$query->setMaxResults(25);
You can check doctrine-extensions for Doctrine2 which have paginator support. These extensions have been made by one of the developer of Doctrine2. You can review these here.
Hope this help.
Regards,
Matt
I think this is as concise as it gets:
$qb = $repo->createQueryBuilder('entity');
$qb->select('COUNT(entity)');
$count = $qb->getQuery()->getSingleScalarResult();
Where $repo is of type Doctrine\ORM\EntityRepository