CakePhp Containable too many queries - mysql

I'm using CakePHP 2.5.2 and having a bit of trouble searching for data efficiently.
In my application I've 3 tables, teams, players, skills... In teams there are 80 records, players 2400 records, skills 2400 records... I want to calculate the average skill of a team...
//Team model
public $actsAs = array('Containable');
public $hasMany = array('Player');
//Player model
public $actsAs = array('Containable');
public $hasOne = array('Skill');
public $belongsTo = array('Team');
//Skill model
public $actsAs = array('Containable');
public $belongsTo = array('Player');
My research is:
$team = $this->Team->find('all', array(
'contain' => array(
'Player' => array(
'Skill'
)
),
));
$this->set('team', $team);
that gives the expected result:
Array
(
[0] => Array
(
[Team] => Array
(
[id] => 1
[name] => my_team_name
)
[Player] => Array
(
[0] => Array
(
[id] => 000000419
[name] => Name
[surname] => Surname
[age] => 21
[team_id] => 1
[Team_id] => 1
[Skill] => Array
(
[id] => 20
[player_id] => 000000419
[skill] => 599
)
), ecc.....
This structure use at least 1680 queries... that are too much for me...
I've tried an other way, that involve just one query, returns a bad data structure but all the information that i need (also redundant). unfortunately follow this way i can not iterate in View to display what i need.
$player = $this->Team->Player->find('all', array(
'contains' => array(
'Skill',
),
that returns
Array
(
[0] => Array
(
[Player] => Array
(
[id] => 000000400
[nome] => my_player_name
[cognome] => my_player_surname
[nation_id] => 380
[age] => 29
[team_id] => 2
)
[Team] => Array
(
[id] => 2
[nome] => my_team_name
)
[Skill] => Array
(
[id] => 1
[player_id] => 000000400
[average] => 632
)
)
ecc.
Is there a way to iterate in VIEV to get the average skill of every team? Any other solutions?
Thanks!

You can use my plugin to solve this issue if you can upgrade CakePHP to 2.6 or later. The plugin has a high compatibility with ContainableBehavior, but generates better queries.
I think that the find operation will execute only 2 queries then.
I would be happy if you try it.
https://github.com/chinpei215/cakephp-eager-loader
Usage
1. Enable EagerLoader plugin
// In your model
$actsAs = ['EagerLoader.EagerLoader'];
If you are afraid that loading my plugin breaks something somewhere, you can also enable it on the fly.
// On the fly
$this->Team->Behaviors->load('EagerLoader.EagerLoader');
2. Execute the same find operation
$this->Team->find('all', ['contain' => ['Player' => ['Skill']]]);
3. See the query log
You will see the query log such as the following:
SELECT ... FROM teams AS Team WHERE 1 = 1;
SELECT ... FROM players AS Player LEFT JOIN skills AS Skill ON Player.id = Skill.player_id WHERE Player.id IN ( ... );

if you feeling that query searching so many tables (ie, models) then
you can unbind those model, before performing search with find()
if you want to fetch some particular column of a table, then remove
others column by selecting "fields" in find().

Related

laravel relationship with json column

//controller
$promotion = Promotion::findOrFail($id);
//return
Array
(
[id] => 2
[en_title] => promo1
[game_id] => Array
(
[0] => 3
[1] => 4
[2] => 5
)
[amount] => 100.00
[start_at] => 2021-02-22
[end_at] => 2222-02-22
[status] => 1
)
//model promotion
class Promotion extends Model
{
use HasFactory;
protected $guarded = [];
protected $casts = [
'game_id' => 'array'
];
public function getAllGames()
{
return $this->belongsTo(Game::class, 'game_id', 'id');
}
}
Question:
Currently, I have 2 tables which are games and promotion, but I get trouble when coming into a relationship because the column of game_id inside the promotion table is a JSON, so that is hard to join it. Is there any work around can easily join them together in order to retrieve games data?
make many-to-many relationship between your games and promotion tables,
put your game_ids in pivot table (game_promotion) instead of JSON field,
Many To Many Relationships

How to have relationship in Laravel 5.7 based on a json data key saved in a table column?

I am using this Staudenmein package in Laravel and referring to this answer given by the package owner himself.
I have two tables, pets and notifications with models Pet and Notification.
The notifications table has a column called data which is of JSON dataType and stores JSON data
{"pet_id":"4","pet_type_id":1,"lost_report_id":3,"pet_sighting_id":21,"latitude":"22.676846","longitude":"88.338509"}
The key pet_id denotes the id column of the pets table. I need a relationship so that I can fetch the name of the pet from pets table.
By referring to the answer link given above, I wrote my Notification model like this:-
namespace App\Models;
use DB, App, Auth, Hash, Lang, Mail, Config, Exception, Validator, Globals;
use Illuminate\Database\Eloquent\Model;
use \Staudenmeir\EloquentJsonRelations\HasJsonRelationships;
use App\User;
use App\Models\AdminConfig;
use App\Models\ReceivedAppNotification;
class Notification extends Model
{
protected $casts = [
'data' => 'json'
];
public function notificationPet()
{
return $this->belongsTo('App\Models\Pet', 'data->pet_id');
}
}
When I am running the query like this:-
$notificationQuery = Notification::with('notificationPet')
->whereRaw("FIND_IN_SET('$userId', in_app_notification_receiver)")
->where(array(
'status' => Globals::SMALL_CHAR_ACTIVE,
'is_delete' => Globals::SMALL_CHAR_NO,
))->get()->toArray();
I get the notificationPet relationship as empty, ie. the data-set is like this:-
Array
(
[id] => 10
[title] =>
[message] =>
[data] => Array
(
[pet_id] => 4
[latitude] => 22.676846
[longitude] => 88.338509
[pet_type_id] => 1
[lost_report_id] => 3
[pet_sighting_id] => 34
)
[no_of_in_app_notification_receiver] => 2
[no_of_push_notification_receiver] => 1
[from_user] => 22
[in_app_notification_receiver] => 2,23
[push_notification_receiver] => 2
[status] => a
[is_delete] => n
[push_notification_sent] => n
[created_date] => 2020-03-19 13:23:17
[modified_date] => 2020-03-19 13:23:17
[created_at] => 2020-03-19 13:23:17
[updated_at] => 2020-03-19 13:23:17
[notification_pet] =>
)
However, I have a record in pets table with id = 4, already. So the relationship should not be empty.
What am I doing wrong?
Change:
protected $casts = [
'data' => 'json'
];
To:
protected $casts = [
'data' => 'array'
];

Json issue when migrating from elasticseach 6 to 7

we use elasticsearch to power our classified search engine Listings360 Kenya.
In Elasticsearch version 6 during the search we could get the total hits documents count used for pagination here from this json output
Array
(
[took] => 3
[timed_out] =>
[_shards] => Array
(
[total] => 5
[successful] => 5
[skipped] => 0
[failed] => 0
)
[hits] => Array
(
[total] => 30540
[max_score] =>
[hits] => Array
(
[0] => Array
(
Now the exact same search with elasticsearch 7 give the following json output
Array
(
[took] => 14
[timed_out] =>
[_shards] => Array
(
[total] => 1
[successful] => 1
[skipped] => 0
[failed] => 0
)
[hits] => Array
(
[total] => Array
(
[value] => 10000
[relation] => gte
)
[max_score] =>
[hits] => Array
(
[0] => Array
(
You can see that i don't have the [hits][total] anymore which is used for pagination purpose.
Any idea how to get that back
Thank you for your help
jap, that´s one of the breaking changes in 7.0.
Have a look at the search param track_total_hits which forces the count to always be accurate. Nevertheless, the new format will still apply and you need to patch your application (that's why it's a breaking change).
Here is more detailed info regarding the new response structure.

Yii2 - Count and sum not include of result of ActiveQuery

Basically I have a legacy query in mysql that I will be implement into ActiveRecord,
Legacy Way, as expected
SELECT
a.container_seal,
a.size ,
count(a.size) as bundles,
sum(a.piece) as pieces
FROM pipe a
WHERE a.outgoing_pipe_id IS NULL
GROUP by a.container_seal, a.size
ORDER by a.container DESC
AR Way
$modelPipe = Pipe::find()
->select([
"container_seal",
"size",
"count(size) as bundles",
"sum(piece) as pieces"
])
->where(['outgoing_pipe_id' => NULL])
->groupBy(['container_seal', 'size'])
->orderBy(['container' => SORT_DESC])
->all();
But why, when I debug it,
<pre>
<?php
print_r($modelPipe);
?>
</pre>
The count and sum is not into.
Array
(
[0] => app\models\hanwa\Pipe Object
(
[_attributes:yii\db\BaseActiveRecord:private] => Array
(
[container_seal] => TEMU6099067/ EMCCSQ6566
[size] => 15 x 35 x 0.85 x 6000
)
[_oldAttributes:yii\db\BaseActiveRecord:private] => Array
(
[container_seal] => TEMU6099067/ EMCCSQ6566
[size] => 15 x 35 x 0.85 x 6000
)
[_related:yii\db\BaseActiveRecord:private] => Array
(
)
[_errors:yii\base\Model:private] =>
[_validators:yii\base\Model:private] =>
[_scenario:yii\base\Model:private] => default
[_events:yii\base\Component:private] => Array
(
)
[_behaviors:yii\base\Component:private] => Array
(
)
)
[1] => app\models\hanwa\Pipe Object
(
[_attributes:yii\db\BaseActiveRecord:private] => Array
(
[container_seal] => TEMU6099067/ EMCCSQ6566
[size] => 35 x 35 x 0.75 x 6000
)
Is it Yii2 have another way to use sum and count in case 'select' ?
You shoudl add the pubblic var for bundles and pieces in your pipe model
(for recive the result of query )
class Pipe extends \yii\db\ActiveRecord
{
public $bundles;
public $pieces;
......

Set and fetch bindModel query in cake template file

$categ = $this->FreeadsCategory->bindModel( array( 'hasMany' => array( 'Subcategory' => array('foreignKey' => 'category_id', 'order'=>'id ASC') ) ) );
$data = $this->FreeadsCategory->findById($i);
$this->set("datas", $data);
I am not able to fetch the datas in view page using cakephp
If i give pr($datas); showing nothing in ctp file
If i print the data in controller i am getting the following array structure
Array
(
[FreeadsCategory] => Array
(
[id] => 1
[uuid] => 51512434-e4c4-441b-b90e-16f8732d5573
[category] => Automobiles
[status] => Active
)
[Subcategory] => Array
(
[0] => Array
(
[id] => 1
[uuid] => 4ea15f22-adf0-4020-b35d1-052ff9ff9a27
[category_id] => 1
[subcategory] => Cars/Cabs/Jeeps
[status] => Active
)
[1] => Array
(
[id] => 5
[uuid] => 51cec363-e7ac-4095-a86b-0ccdf260d1b4
[category_id] => 1
[subcategory] => Buses/Lorries
[status] => Active
)
)
You don't fetch data in views, that violates the MVC pattern. Technically there are ways to do it but it's plain wrong, you'll end up with unmaintanable garbage code.
I really recommend you to get started by reading about the MVC design pattern and to do the CakePHP blog tutorial first to get a minimum of understanding of how CakePHP works.