Add multiple count fields of contained model to query in cakephp 3 - mysql

I want to have in my model, instead of the complete set of entries of the models contained by another one, just the quantity of them. I could do this by adding the "size" field to the resultset, but I'd like to do this in the query, as I want to paginate and order the results dinamically. I am using this code, but for some reason, if the first count is different from zero, both count fields have the same value, which is the value of the second count field.
$query = $this->Users->find('all')
->contain(['Likes','Favs']);
$query
->select(['like_count' => $query->func()->count('Likes.id')])
->leftJoinWith('Likes')
->group(['Users.id'])
->autoFields(true);
$query
->select(['fav_count' => $query->func()->count('Favs.id')])
->leftJoinWith('Favs')
->group(['Users.id'])
->autoFields(true);
$this->paginate['sortWhitelist'] = [
'name',
'email',
'last_login',
'fav_count',
'like_count',
];
I would like to know why this happens and if there is any other way to do what I attempt, which would be to have ('name', email, 'last_login', quantity of entries in Likes with the user's id, quantity of entries in Favs with the user's id). I have tried using join() to do the left join, but I haven't been able to obtain the result I want.

If you have multiple joins, then you need to count with DISTINCT, eg:
COUNT(DISTINCT Likes.id)
This is because your result will contain Likes * Favs number of rows, as for every joined like, all favs will be joined, ie for 2 likes and 10 favs you'd end up with 20 rows in total. A regular COUNT() would include every single one of those rows.
Also note that you don't need to repeat all that grouping, etc stuff, and you can use a callable for select() to avoid breaking up the builder.
$query = $this->Users
->find('all')
->select(function (\Cake\ORM\Query $query) {
return [
'like_count' => $query->func()->count(
$query->func()->distinct(['Likes.id' => 'identifier'])
),
'fav_count' => $query->func()->count(
$query->func()->distinct(['Favs.id' => 'identifier'])
),
];
})
->autoFields(true)
->contain(['Likes', 'Favs'])
->leftJoinWith('Likes')
->leftJoinWith('Favs')
->group(['Users.id']);
Using the functions builder to generate the DISTINCT is a workaround, as there is no API yet that would allow to specifically generate a keyword. The result will be something like DISTINCT(Likes.id), but it will work fine, the parentheses will be interpreted as part of the expression after the keyword, not as part of a function call.

Related

Laravel query builder not returning the full row if it does not find a join with another table

Here, my currently working query is
$results = DB::table('amenities as a')
->leftJoin('amenity_values as av','av.amenity_id','=','a.id')
->leftJoin('units_amenities_values as uav','uav.amenity_value_id','=','av.id')
->leftJoin('units as u','uav.unit_id','=','u.id')
->leftJoin('amenity_pricing_reviews as apr','apr.unit_id','=','u.id')
->select('a.id as amenity_id','a.amenity_name','a.category_id', 'av.amenity_value','u.id as unit_id','u.unit_number','apr.dom','apr.building_id')
->where('a.property_id', $data['property_id'])
->whereIn('apr.building_id', $data['building_ids'])
->whereNull('apr.deleted_at')
->whereNull('u.deleted_at')
->whereNull('av.deleted_at')
->whereNull('a.deleted_at')
->orderBy('a.amenity_name','asc')
->get()
->groupBy(['category_id','unit_id']);
Here, I have joined to a table amenity_pricing_reviews. In this relationship whenever it could not find the related rows in the amenity_pricing_reviews table it is discarding the full rows:
However, I want to get these rows with an empty value for those columns from that table. Something like:
amenity_id => value
amenity_name => value
category_id => value
amenity_value => value
unit_id => value
unit_number => value
dom =>
building_id =>
Also, I have done a lot of other things based on the result of this query so I want to make minimal changes to the structure of the end result.
Your whereIn condition can't succeed if the amenity pricing review doesn't exist, so it effectively changes your left joins into inner joins. Perhaps you want that to be just a condition of the join?
->leftJoin('amenity_pricing_reviews as apr', function($join) { $join->on('apr.unit_id','=','u.id')->whereIn('apr.building_id', $data['building_ids']) })
Try join instead of leftJoin. This should help

How to use grouby and count using laravel ORM?

I have an address table where there are many fields like city, ward, tole, district, latitude, longitude. I need to count the number of rows for distinct district. For eg I have following database table as show in screenshot:
I have the rows containing Kathmandu, Bhaktapur and Jhapa as districts. Now I need to get the number of rows containing Kathmandu as district and likewise.
The output should be like this:
array( "Kathmandu"=> 4 , "Bhaktapur" => 1 , "Jhapa"=>1 );
I found multiple solution to the problem in which DB query is used. But I need it ORM way.
You could use aggregated query
$districts = DB::table('address')
->select('district', DB::raw('count(*) as total'))
->groupBy('district')
->pluck('total','district')
->all();

Count a field in database

I want to count a field name 'leave_policy' depending on the name of 'leave_policy' and I am using joins to do it. My database is like this
https://imgur.com/a/gR3Dw
and I want to show count in applied section. For example if I want to count all "Urgent Leaves" and "Paternal Leaves" seperately I have applied till now. https://imgur.com/a/dvjuX
$join = DB::table('leaves_policy')
->join('leaves_policies', 'leaves_policy.leave_policy', '=', 'leaves_policies.title')
->join('leaves_requests', 'leaves_policy.requested_by' , '=', 'leaves_requests.requested_by')
->select('leaves_policy.*', 'leaves_policies.title', 'leaves_policies.total_no_of_leaves_allowed_per_year',
'leaves_policies.no_of_months_leaves_valid', 'leaves_policies.max_leaves_per_month', 'leaves_policies.max_con_leaves_per_month',
'leaves_requests.leave_status', DB::raw('COUNT(leaves_policy.leave_policy) as count'))
->groupBy('id')
->get();
For example,
I have a table Leave_table. leave_policy and purpose are the fields.
I am displaying the leave count based on the leave_policy column. i have used the below query to get the count.
select leave_policy,count(leave_policy) from leave_table group by leave_policy

When i try to display the count value of one column it counts the no. of arrays stored in a single cell of the same row on the same table

I have written the following function to display a table consisting of
recipe name, description, cusine , ........ ..., ingredients AND LIKES.
Everything works fine but the likes column doesnot show the no. of likes bu instead sows the no. of ingredients of the recipe
public function rec(){
$ing = inglist::all();
$rcusine=recipecusine::all();
$rtype=recipetype::all();
$rec = DB::table('recipe_list')
->select('recipe_list.recipe_id','recipe_list.Recipe_name',
'recipe_list.Recipe_desc','recipe_list.Recipe_duration',
DB::raw('group_concat(ing_list.Ing_name separator ",") as recipe_ingredients'),
'recipe_cusine.Cusine_name', 'recipe_type.Recipe_type_name','recipe_list.image',
DB::raw('count(likerecipes.likecount) as likes'))
->join('recipe_inglist', 'recipe_list.recipe_id','=','recipe_inglist.Recipe_id')
->join('ing_list', 'recipe_inglist.Ing_id','=','ing_list.ing_id')
->join('recipe_cusine', 'recipe_list.Recipe_cusine_id','=','recipe_cusine.cusine_id')
->join('recipe_type', 'recipe_list.Recipe_type_id','=','recipe_type.Recipe_typeID')
->join( 'likerecipes', 'recipe_list.recipe_id', '=', 'likerecipes.recipe_id')
->where('recipe_list.recipe_id','>=','1')
->groupBy('recipe_list.recipe_id', 'recipe_list.recipe_name','recipe_list.recipe_desc','recipe_list.recipe_duration', 'recipe_cusine.Cusine_name','recipe_type.Recipe_type_name','recipe_list.image' )->get() ;
/* var_dump($rec);
die();*/
return view('recipe', ['ingredients'=>$ing, 'cusine'=>$rcusine, 'type'=>$rtype,'recipe'=>$rec]);
}
the output i get is
and this is my likerecipes table
can anyone help me where i am wrong.
Because of the joins, your data is duplicated through the records. Since the likerecipes table seems to store like votes casted one by one identified by an id field uniquely, I would count the distinct likerecipes.id values per group:
'count(distinct likerecipes.id) as likes'
I would also introduce the distinct to the group_concat() to make sure that multiple like votes do not make the same ingridients appear multiple times:
'group_concat(distinct ing_list.Ing_name separator ",") as recipe_ingredients'

Trouble counting rows with specific value - Doctrine, Symfony2, mysql

I'm working on querying my mysql database via doctrine in a symfony2 app. I have a basic table set up that includes an id number ('id'), name ('name'), and a last column for if the person has been contacted ('contacted'), depicted with 0 or 1. I can query and get the number of total inquiries (depicted in the controller with $inquiryCountTotal just fine.
I'm struggling to count the rows that have been contacted. I figure I can either COUNT the rows with a value of 1 in the contacted column or I could just SUM all the rows in the contacted column.
For some reason it seems to be summing the ids, as I have 8 ids and it's spitting a number of 36.
Where am I going wrong? Thanks in advance!
public function indexAction()
{
$em = $this->getDoctrine()->getManager();
$entities = $em->getRepository('EABundle:Inquiry')
->findBy(array(), array('id'=>'DESC'));
$inquiryCountTotal = $em->createQuery("
SELECT count(id)
FROM EABundle:Inquiry id
")->getSingleScalarResult();
//This is the part I'm struggling with...
$inquiryCount = $em->createQuery("
SELECT sum(contacted)
FROM EABundle:Inquiry contacted
")->getSingleScalarResult();
return $this->render('EABundle:Inquiry:index.html.twig', array(
'entities' => $entities,
'inquiryCount' => $inquiryCount,
'inquiryCountTotal' => $inquiryCountTotal
));
}
Doctrine is interpreting the alias as the id of the entity.
Try this:
$inquiryCount = $em->createQuery("
SELECT sum(i.contacted)
FROM EABundle:Inquiry i
")->getSingleScalarResult();